From ef66c5675135904731a2ff9fa08c117ed6dd9758 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 28 Aug 2026 15:18:05 -0500 Subject: [PATCH 01/12] chore(all): Replace exceljs due to lack of maintenance --- .../jest.config.js | 1 - .../package-lock.json | 1443 ++++------------- accessibility-checker-extension/package.json | 2 +- accessibility-checker-extension/preprocess.js | 23 +- .../test/package-lock.json | 1221 ++------------ .../test/package.json | 2 +- .../test/support/steps/steps_excel.ts | 31 +- accessibility-checker/package.json | 4 +- accessibility-checker/src/package.json | 4 +- common/module/package-lock.json | 68 +- common/module/package.json | 4 +- common/module/src/report/ACReporterXLSX.ts | 1137 +++++-------- .../boilerplates/package-lock.json | 144 +- .../package-lock.json | 136 +- cypress-accessibility-checker/package.json | 14 +- karma-accessibility-checker/package.json | 4 +- report-react/package-lock.json | 439 +++-- rule-server/package-lock.json | 64 +- .../boilerplates/vitest/package-lock.json | 334 ++-- .../package-lock.json | 376 +++-- vitest-accessibility-checker/package.json | 4 +- .../src/package-lock.json | 294 ++-- vitest-accessibility-checker/src/package.json | 4 +- 23 files changed, 1833 insertions(+), 3920 deletions(-) diff --git a/accessibility-checker-extension/jest.config.js b/accessibility-checker-extension/jest.config.js index 37549d3b3..337e7eb44 100644 --- a/accessibility-checker-extension/jest.config.js +++ b/accessibility-checker-extension/jest.config.js @@ -187,7 +187,6 @@ module.exports = { "testTimeout": 60000, "moduleNameMapper": { // Force module uuid to resolve with the CJS entry point, because Jest does not support package.json.exports. See https://github.com/uuidjs/uuid/issues/451 - // Note that this comes through the exceljs module "uuid": require.resolve('uuid'), "\\.(css|less|scss|sass)$": "identity-obj-proxy" }, diff --git a/accessibility-checker-extension/package-lock.json b/accessibility-checker-extension/package-lock.json index 326c876f7..117671734 100644 --- a/accessibility-checker-extension/package-lock.json +++ b/accessibility-checker-extension/package-lock.json @@ -12,14 +12,14 @@ "@carbon/react": "^1.72.0", "@carbon/themes": "^11.17.0", "dotenv-webpack": "^7.0.3", - "exceljs": "^4.4.0", "markdown-to-jsx": "^7.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", "react-redux": "^7.2.6", "redux": "^4.1.2", "tabbable": "^5.2.0", - "webext-redux": "^2.1.9" + "webext-redux": "^2.1.9", + "write-excel-file": "^4.1.1" }, "devDependencies": { "@svgr/webpack": "^6.1.2", @@ -1719,13 +1719,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-8.0.0.tgz", + "integrity": "sha512-sL6cvO2IfkSu/iU+zs2S/w01B7A8V7suXSIKEN4hPFFdZoiPGxrj5pAG0lCaqLWiEIrjKzdznIWuaLcxPR53qw==", + "license": "MIT" }, "node_modules/@babel/template": { "version": "7.29.7", @@ -1776,9 +1773,9 @@ } }, "node_modules/@carbon/colors": { - "version": "11.55.0", - "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.55.0.tgz", - "integrity": "sha512-02XkYCoo1GASrux+UofsPW+cgX58wf4LM5kpsitewvPuiA3/XI06Zzyss4yw/ammAHr3OruKzPmc/sNQZXlHCQ==", + "version": "11.57.0", + "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.57.0.tgz", + "integrity": "sha512-ji8xOBiCzCmeR/Pg/rDbnViVYDnjSVWRclylQKqeAQNUIsfIWDB69xq/o33lba3vVccVDNrGcGkrVg5My0Ct7g==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -1786,9 +1783,9 @@ } }, "node_modules/@carbon/feature-flags": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-1.6.0.tgz", - "integrity": "sha512-VC6Rweb84VyDqA1wUZzZ/nNnR4QQiDkr5+of6cpzLUbgjLtL5aml9pIvjYeHnYKRVm6FeNFjnHY9wYVaSOvN/g==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-1.8.0.tgz", + "integrity": "sha512-bgdo6JRkG4yBOG58n+qlbBp3qzYrTZ33EEthNQY/ACsZm9gNUlxA7xOwesbNjryzAp4r5s9mKF4ZA6cackLnbQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -1796,20 +1793,20 @@ } }, "node_modules/@carbon/grid": { - "version": "11.59.0", - "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.59.0.tgz", - "integrity": "sha512-sa+56qm1J/CZ2aGMeHRF9ui2YmmXBKdEvLtUV9W6t+ILub0e0/nS12HAEhbiuw8B0IqWjUpIQR6Lzaii6TcYSw==", + "version": "11.61.0", + "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.61.0.tgz", + "integrity": "sha512-kY6Zwi15kpdbT/RM8M7QciK5BVZhb0cEepvoP2uT0a04yTio4QMc8BZxIvXXMi8vf48AowUNkxbhYk8KlAf7EQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/layout": "^11.56.0", + "@carbon/layout": "^11.58.0", "@ibm/telemetry-js": "^1.5.0" } }, "node_modules/@carbon/icon-helpers": { - "version": "10.79.0", - "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.79.0.tgz", - "integrity": "sha512-sg5bL9Y/Vns4W7iNRaIMoNc/FtuzJE8G5VvCbC8xcrrNoZmfhhiPFHyU8CFhrf19HJdAxOvXShIBxmm3glLAYw==", + "version": "10.81.0", + "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.81.0.tgz", + "integrity": "sha512-3ga+ZpXzo+aL5rGSZu5xEdXGyEzSUGBe0IqvlcFxeav2gcrrE5w0G8ZAvUPsPWJXybjrXKW0CQaGAtsgNkmLLA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -1817,13 +1814,13 @@ } }, "node_modules/@carbon/icons-react": { - "version": "11.85.0", - "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.85.0.tgz", - "integrity": "sha512-+fRNYyqR8aCZRSgMA8sJ+GVfCmS0pK8FaDl9rQDuy4ZqYldZ4Yj8K3YIxmcSLlvTxMmNtGAxoa80xlhXROYDQg==", + "version": "11.87.0", + "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.87.0.tgz", + "integrity": "sha512-s3hYxy2qlWHZPjd44BpKx1jJAjYDWOLxO0xyJEcFiEqbqR3L+Sg+CeWuNR2L18AfslyNHg5wwB2+zASrwDC/yg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/icon-helpers": "^10.79.0", + "@carbon/icon-helpers": "^10.81.0", "@ibm/telemetry-js": "^1.5.0", "prop-types": "^15.8.1" }, @@ -1832,9 +1829,9 @@ } }, "node_modules/@carbon/layout": { - "version": "11.56.0", - "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.56.0.tgz", - "integrity": "sha512-61XxRnFkJdfSmsr30smEexrVOfHFZIzBPlTtW65CkRx8edAakc2eapxrW1sKFIfYQJildWPi7CivAvjA3cnlUg==", + "version": "11.58.0", + "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.58.0.tgz", + "integrity": "sha512-rVqN9tbpDD0rmyrCldAK2xUSjtusEOCxZqazuWgYFrusGsIpkQJ3ROmdHPkMfIgrpIaSr/RBGDbXXea/Qw7yJQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -1842,9 +1839,9 @@ } }, "node_modules/@carbon/motion": { - "version": "11.49.0", - "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.49.0.tgz", - "integrity": "sha512-HMSBS/tf1MVvXVJayw4jdNPsT79hn/fr31sVzowobErp/AyQGYk/t/NE7kFfOsQnARL0I3ITVEZelShfk1N87Q==", + "version": "11.51.0", + "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.51.0.tgz", + "integrity": "sha512-Is/lRo5iCw6XjQ8y4kXl2BepMJqZBYHVrlEnwyd0PJei+qhmTgpFJFSjUwdj9vRGUwPcWbcxEmY1aWa1gK2Rgw==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -1852,28 +1849,28 @@ } }, "node_modules/@carbon/react": { - "version": "1.113.0", - "resolved": "https://registry.npmjs.org/@carbon/react/-/react-1.113.0.tgz", - "integrity": "sha512-R8/Ew0qrBN+haPZDKo/VOHeJHQSjijGFdv4WXl1YsgneZNjU4O6+Nba88xtZbO1Xpfk3gP7CEttDdm4JwxYRdg==", + "version": "1.115.0", + "resolved": "https://registry.npmjs.org/@carbon/react/-/react-1.115.0.tgz", + "integrity": "sha512-nBGgEDQzdJvlB4UI5FJypIslONsEpRTn4Xy3nDenkO7HhdfgIffhCOcKI5H4UsajMKbk/5IovdkPeO1wZTXftQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.27.3", - "@carbon/feature-flags": "^1.6.0", - "@carbon/icons-react": "^11.85.0", - "@carbon/layout": "^11.56.0", - "@carbon/motion": "^11.49.0", - "@carbon/styles": "^1.112.0", - "@carbon/utilities": "^0.23.0", + "@babel/runtime": "^8.0.0", + "@carbon/feature-flags": "^1.8.0", + "@carbon/icons-react": "^11.87.0", + "@carbon/layout": "^11.58.0", + "@carbon/motion": "^11.51.0", + "@carbon/styles": "^1.114.0", + "@carbon/utilities": "^0.25.0", "@floating-ui/react": "^0.27.4", "@ibm/telemetry-js": "^1.5.0", "classnames": "2.5.1", - "copy-to-clipboard": "^3.3.1", + "copy-to-clipboard": "^4.0.0", "downshift": "9.4.0", "es-toolkit": "^1.27.0", "flatpickr": "4.6.13", "invariant": "^2.2.3", - "motion": "^12.42.0", + "motion": "^13.0.0", "prop-types": "^15.8.1", "react-fast-compare": "^3.2.2", "tabbable": "^6.2.0" @@ -1886,23 +1883,19 @@ } }, "node_modules/@carbon/react/node_modules/motion": { - "version": "12.43.0", - "resolved": "https://registry.npmjs.org/motion/-/motion-12.43.0.tgz", - "integrity": "sha512-BQgQbSa9Hn3/mtbib0MK53y6JSANa+YKUKlaYnWzAVDH424RYQ5LVpV3pNiWH00BA2z4ojsSdMzqT7g2FQwjuQ==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/motion/-/motion-13.1.1.tgz", + "integrity": "sha512-WNZoK6xiF+kkTqkZ5K7FDDh6A8BG4i5Hc7KXtW8gtTxkpJFds+hIOrDaQGKjQj/AE/i4hJqAaUHEqp/Qo02y6Q==", "license": "MIT", "dependencies": { - "framer-motion": "^12.43.0", + "framer-motion": "^13.1.1", "tslib": "^2.4.0" }, "peerDependencies": { - "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, "react": { "optional": true }, @@ -1912,24 +1905,20 @@ } }, "node_modules/@carbon/react/node_modules/motion/node_modules/framer-motion": { - "version": "12.43.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.43.0.tgz", - "integrity": "sha512-1eaL3RvR/kAlbG7UYcpMptEyzPoENO0c6w7ZnB3/hh2vSAz/6uGAFn6fdoqTBguNstf3MsFhJHsD/0DHiclG+g==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-13.1.1.tgz", + "integrity": "sha512-B/xn2TPS4f61cEBLFjiYlQFnBZUW1YVj/LM+C+N4OP8Rs95VLEI2ot/RlfBg111la/EiyECFaJJi/A3FWA8MUA==", "license": "MIT", "dependencies": { - "motion-dom": "^12.43.0", - "motion-utils": "^12.39.0", + "motion-dom": "^13.1.1", + "motion-utils": "^13.0.0", "tslib": "^2.4.0" }, "peerDependencies": { - "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, "react": { "optional": true }, @@ -1945,21 +1934,21 @@ "license": "MIT" }, "node_modules/@carbon/styles": { - "version": "1.112.0", - "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.112.0.tgz", - "integrity": "sha512-7gU+nlckjO3n4dmfc/UQ9io6k5CoSYKW92wOJplhrOBtyNEwv00ZWcL/wx8xgVBNSGtg0Asbag2feHbhoapqpw==", + "version": "1.114.0", + "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.114.0.tgz", + "integrity": "sha512-795Z4PO2Tu/nuwFY0HGu2HTZTrKagaCSYf5ILOn/7hcmM+88R8BrNFZC961kxXitZv3RXmY0wV/oqqJ4scOQYA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/colors": "^11.55.0", - "@carbon/feature-flags": "^1.6.0", - "@carbon/grid": "^11.59.0", - "@carbon/layout": "^11.56.0", - "@carbon/motion": "^11.49.0", - "@carbon/themes": "^11.78.0", - "@carbon/type": "^11.64.0", + "@carbon/colors": "^11.57.0", + "@carbon/feature-flags": "^1.8.0", + "@carbon/grid": "^11.61.0", + "@carbon/layout": "^11.58.0", + "@carbon/motion": "^11.51.0", + "@carbon/themes": "^11.80.0", + "@carbon/type": "^11.66.0", "@ibm/plex": "6.4.1", - "@ibm/plex-mono": "1.1.0", + "@ibm/plex-mono": "2.5.0", "@ibm/plex-sans": "1.1.0", "@ibm/plex-sans-arabic": "1.1.0", "@ibm/plex-sans-devanagari": "1.1.0", @@ -1979,40 +1968,44 @@ } }, "node_modules/@carbon/themes": { - "version": "11.78.0", - "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.78.0.tgz", - "integrity": "sha512-v0w90JjmWCq13chVvhQmjgTGRMp47OzKG7lsLJzFcWfK7kI0FvLIMWbS/tpKOP9Z6tWOjZhsSZm8UaaCd3cXQg==", + "version": "11.80.0", + "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.80.0.tgz", + "integrity": "sha512-SqtfqwReq1SRrBoC121Bllrh0DvW2j/LWFo/zVn+lblh+AJlLZsmeBC9oyxphpp8GpHfLhjmeg1J2hfs0AVX4A==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/colors": "^11.55.0", - "@carbon/layout": "^11.56.0", - "@carbon/type": "^11.64.0", + "@carbon/colors": "^11.57.0", + "@carbon/layout": "^11.58.0", + "@carbon/type": "^11.66.0", "@ibm/telemetry-js": "^1.5.0", "color": "^4.0.0" + }, + "engines": { + "node": ">=22" } }, "node_modules/@carbon/type": { - "version": "11.64.0", - "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.64.0.tgz", - "integrity": "sha512-ejnpUIbmyEbGkKWX3mzojKa3lOc3Jhoqhy7b4f2zi/nAV0uGu8KMXw978Cq/op3/WwOGYzwRf2viqTw6NNLWPQ==", + "version": "11.66.0", + "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.66.0.tgz", + "integrity": "sha512-8y9WtdXqqKAGnOyZvkRP7jqqQe+WcdRQDfsgOcpusszIoSBSVs2dv4gEwHjMYmzansLhsCUBNocSfWNFhkVDOg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/grid": "^11.59.0", - "@carbon/layout": "^11.56.0", + "@carbon/grid": "^11.61.0", + "@carbon/layout": "^11.58.0", "@ibm/telemetry-js": "^1.5.0" } }, "node_modules/@carbon/utilities": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@carbon/utilities/-/utilities-0.23.0.tgz", - "integrity": "sha512-QLWHKvCEj5wBa4xcQv7xsddqrUXIi9z1Qri7nLGTd6dHOBcskmx8EpfvUvRgL0Hbd+Nd3zf3qT2ztuIvuRCzMA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@carbon/utilities/-/utilities-0.25.0.tgz", + "integrity": "sha512-00zsQ3ldFKQUb1CrQ47pMZHDDigY9gR5OiusxdugyGBJmZUMg2FhycHQD94W35YYv28sG7ILNQJQ/x1tehDQzQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@ibm/telemetry-js": "^1.6.1", - "@internationalized/number": "^3.6.1" + "@internationalized/number": "^3.6.1", + "temporal-polyfill": "^1.0.4" } }, "node_modules/@discoveryjs/json-ext": { @@ -2025,47 +2018,6 @@ "node": ">=10.0.0" } }, - "node_modules/@fast-csv/format": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", - "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isboolean": "^3.0.3", - "lodash.isequal": "^4.5.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0" - } - }, - "node_modules/@fast-csv/format/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "license": "MIT" - }, - "node_modules/@fast-csv/parse": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", - "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.groupby": "^4.6.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0", - "lodash.isundefined": "^3.0.1", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/@fast-csv/parse/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "license": "MIT" - }, "node_modules/@floating-ui/core": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", @@ -2136,9 +2088,9 @@ } }, "node_modules/@ibm/plex-mono": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ibm/plex-mono/-/plex-mono-1.1.0.tgz", - "integrity": "sha512-hpsdRxR3BRJkC6wGM4MZcUFD6C8M+mmK76RtAy/hlsfPro9FzpXVdIWC+G3jeQOXof109dxlUvmeKxpeKUG68A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ibm/plex-mono/-/plex-mono-2.5.0.tgz", + "integrity": "sha512-STBJIPxPomOYPmBMO7z5TKPJUotAF9u3gAUumTqVgwgrAO+K4FRNh0MlhsoJjKhJKsMbBJR10/bk4inkj/wc1w==", "hasInstallScript": true, "license": "OFL-1.1", "dependencies": { @@ -2274,9 +2226,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -2572,13 +2524,13 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.1.0.tgz", - "integrity": "sha512-RDLpio3fH/qrj5k4DVY6eyiN8tCS0Zovd/6jW//n605oeqkWcUjn+3k+9ZtZBnbwMpsu0F7xDIiKXvVmG5c5Bw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.2.1.tgz", + "integrity": "sha512-KDz+3qDRdBAlRlMjmKyj6dEs33YHTk/xRHEENSXq6TNnhgoU15ruSHtEBeVF6OZ9tBDY55Se4P0nFMNsipzU9A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "modern-tar": "^0.7.6", + "modern-tar": "^0.8.0", "yargs": "^18.0.0" }, "bin": { @@ -3298,9 +3250,9 @@ "license": "Apache-2.0" }, "node_modules/accessibility-checker": { - "version": "4.0.29", - "resolved": "https://registry.npmjs.org/accessibility-checker/-/accessibility-checker-4.0.29.tgz", - "integrity": "sha512-7HFBcLNaN2ABkKrVxFHJX1Dh+3oC1sxMLMkoI3Qnz+UBZBXqaUcRujzYs+/j7i4ZGoAxZWLo96SqDE9Y4t1VUA==", + "version": "4.0.31", + "resolved": "https://registry.npmjs.org/accessibility-checker/-/accessibility-checker-4.0.31.tgz", + "integrity": "sha512-MXMaFXbRGEM/7Y1LBMq6jbHqPqkSfPKtIEXfjz9eclEjxk9FR/vug00oFiZj+jXyOR5jENLOYIrcqDwPU0ShFw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -3336,13 +3288,13 @@ } }, "node_modules/adm-zip": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", - "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", + "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0" + "node": ">=14.0" } }, "node_modules/agent-base": { @@ -3429,75 +3381,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "license": "MIT", - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3541,12 +3424,6 @@ "node": ">=4" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3555,9 +3432,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "dev": true, "license": "MIT", "dependencies": { @@ -3613,32 +3490,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "dev": true, "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", - "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -3657,15 +3515,6 @@ "node": ">=10.0.0" } }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "license": "Unlicense", - "engines": { - "node": ">=0.6" - } - }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -3676,36 +3525,6 @@ "node": "*" } }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "license": "MIT", - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", - "license": "MIT" - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -3717,6 +3536,7 @@ "version": "1.1.18", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -3724,9 +3544,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", - "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", "funding": [ { "type": "opencollective", @@ -3743,11 +3563,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.44", - "caniuse-lite": "^1.0.30001806", - "electron-to-chromium": "^1.5.393", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" @@ -3756,62 +3576,12 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/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==", "license": "MIT" }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -3871,9 +3641,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "funding": [ { "type": "opencollective", @@ -3890,18 +3660,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "license": "MIT/X11", - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3957,16 +3715,16 @@ } }, "node_modules/chromedriver": { - "version": "151.0.2", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-151.0.2.tgz", - "integrity": "sha512-p2NI0qrBSpoksa9S4lxqpML28I1U1oMtNPyvbjiMlBB+JOn9qRQC/cuiAWPf36lAdsYgrqhQczb12UH2he04MQ==", + "version": "152.0.2", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-152.0.2.tgz", + "integrity": "sha512-w/trjzSjQC8vHHwl4e+WXBGPRN3XnrsY14q/FdxCY8GtTUIlB+wH1gn/Kz3CHpdmbsouUEGal6E8bjEEz72pZg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@testim/chrome-version": "^1.1.4", - "adm-zip": "^0.5.18", - "axios": "^1.18.1", + "adm-zip": "^0.6.0", + "axios": "^1.19.0", "compare-versions": "^6.1.1", "proxy-agent": "^8.0.2", "proxy-from-env": "^2.1.0", @@ -4047,9 +3805,9 @@ } }, "node_modules/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -4196,21 +3954,6 @@ "dev": true, "license": "MIT" }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/compute-scroll-into-view": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", @@ -4221,6 +3964,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/convert-source-map": { @@ -4231,13 +3975,10 @@ "license": "MIT" }, "node_modules/copy-to-clipboard": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", - "license": "MIT", - "dependencies": { - "toggle-selection": "^1.0.6" - } + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-4.0.2.tgz", + "integrity": "sha512-gklSft7IuhriZKHKpuoA1fpJSLPNgvUMWMo5BlnzAJm0zNKnznoSv23IjtNqclx8eKi6ZcdvFFzYEER/+U1LoQ==", + "license": "MIT" }, "node_modules/copy-webpack-plugin": { "version": "14.0.0", @@ -4264,25 +4005,22 @@ } }, "node_modules/core-js-compat": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", - "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", + "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.28.1" + "browserslist": "^4.28.7" + }, + "engines": { + "node": ">=6.4.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -4300,31 +4038,6 @@ "node": ">=10" } }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "license": "MIT", - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -4494,12 +4207,6 @@ "node": ">= 20" } }, - "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", - "license": "MIT" - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -4593,9 +4300,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1653615", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1653615.tgz", - "integrity": "sha512-pGVkY3T/qXxAp2nFPodwYqOevk6ncNMSmvL8QfRCx5ZWGd6Vor7AFNmyaA8Zs6uJyP1QAfjuLandCgvSix1BNA==", + "version": "0.0.1666840", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1666840.tgz", + "integrity": "sha512-gCcO42XCHKEs7Ag0S7aGYsnJ7hlgrO3qderYqeiY0Eqk+0GFfuvT13IA0hHreJTa2KCdDVyGMeOhdMNmrrTjVg==", "dev": true, "license": "BSD-3-Clause" }, @@ -4748,6 +4455,15 @@ "react": ">=16.12.0" } }, + "node_modules/downshift/node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/downshift/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -4769,49 +4485,10 @@ "node": ">= 0.4" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "license": "BSD-3-Clause", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexer2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/electron-to-chromium": { - "version": "1.5.400", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.400.tgz", - "integrity": "sha512-96EWDNjM59SYflgeV5Ylsf4EMiq1a25YjCnJH7cxn/AF2H3pILRweaUnoLax0yKHWdpOzY6JKEu45e8irqZIHA==", + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -4831,15 +4508,6 @@ "node": ">= 4" } }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.24.5", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", @@ -4910,9 +4578,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "license": "MIT" }, "node_modules/es-object-atoms": { @@ -4945,14 +4613,15 @@ } }, "node_modules/es-toolkit": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", - "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", "license": "MIT", "workspaces": [ "docs", "benchmarks", - "tests/types" + "tests/types", + "tests/browser-compat" ] }, "node_modules/escalade": { @@ -4996,28 +4665,6 @@ "source-map": "~0.6.1" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -5032,22 +4679,11 @@ "node": ">=4" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -5072,39 +4708,6 @@ "node": ">=0.8.x" } }, - "node_modules/exceljs": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", - "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", - "license": "MIT", - "dependencies": { - "archiver": "^5.0.0", - "dayjs": "^1.8.34", - "fast-csv": "^4.3.1", - "jszip": "^3.10.1", - "readable-stream": "^3.6.0", - "saxes": "^5.0.1", - "tmp": "^0.2.0", - "unzipper": "^0.10.11", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/fast-csv": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", - "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", - "license": "MIT", - "dependencies": { - "@fast-csv/format": "4.3.5", - "@fast-csv/parse": "4.3.6" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5119,9 +4722,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.6.tgz", + "integrity": "sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==", "funding": [ { "type": "github", @@ -5162,6 +4765,12 @@ } } }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT" + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -5230,34 +4839,13 @@ "node": ">= 6" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5360,6 +4948,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -5668,32 +5257,6 @@ "node": ">=4" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, "node_modules/immutable": { "version": "5.1.9", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", @@ -5742,6 +5305,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -5752,6 +5316,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, "license": "ISC" }, "node_modules/interpret": { @@ -5774,9 +5339,9 @@ } }, "node_modules/ip-address": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz", - "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", + "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", "dev": true, "license": "MIT", "engines": { @@ -5910,12 +5475,6 @@ "node": ">=v0.10.0" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5954,9 +5513,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -6015,48 +5574,6 @@ "node": ">=6" } }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -6077,57 +5594,6 @@ "node": ">= 8" } }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "license": "MIT", - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -6148,12 +5614,6 @@ "dev": true, "license": "MIT" }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", - "license": "ISC" - }, "node_modules/loader-utils": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", @@ -6208,85 +5668,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "license": "MIT" - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "license": "MIT" - }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "license": "MIT" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "license": "MIT" - }, - "node_modules/lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "license": "MIT" - }, - "node_modules/lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", - "license": "MIT" - }, - "node_modules/lodash.isnil": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", - "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT" - }, - "node_modules/lodash.isundefined": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", - "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", - "license": "MIT" - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "license": "MIT" - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6414,6 +5795,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -6426,21 +5808,22 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minimizer-webpack-plugin": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.6.1.tgz", - "integrity": "sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.8.0.tgz", + "integrity": "sha512-2cT9+goJfBhtMz+gJqejSf09ClgmYhPhccRb/fb0ztVbixt0BkO8mRuI26FoPPuUNkRk6iEDryWAIouc5W8eJA==", "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", + "@jridgewell/trace-mapping": "^0.3.31", "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "terser": "^5.31.1" + "schema-utils": "^4.3.3", + "terser": "^5.51.0" }, "engines": { "node": ">= 10.13.0" @@ -6502,6 +5885,7 @@ "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.6" @@ -6511,9 +5895,9 @@ } }, "node_modules/modern-tar": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.7.tgz", - "integrity": "sha512-t9VmxaqrmANnEOBhpSDI6HD192Ge48k8vmWqQQL7hSFEqHEYwZbbsu49+aKLWZeRvFs3j1pMhXOqqF4kPlvjkQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.8.4.tgz", + "integrity": "sha512-gN54ddmyzEg10orwZ2u4OOv+bjpMWdIl5jIkodK97bMq8QBSL5c0D7YX0lT1Ooz+99S7+PvFbnxzdjgHo1r41g==", "dev": true, "license": "MIT", "engines": { @@ -6521,18 +5905,18 @@ } }, "node_modules/motion-dom": { - "version": "12.43.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.43.0.tgz", - "integrity": "sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-13.1.1.tgz", + "integrity": "sha512-XSf8VYWSB6G/0IY3rWVbyLcxWXtAVHkN1PQE2agTaCv3u8RGvbwu56TyyR/MNzBqqNavEBTZzErcxI1TxBrjcA==", "license": "MIT", "dependencies": { - "motion-utils": "^12.39.0" + "motion-utils": "^13.0.0" } }, "node_modules/motion-utils": { - "version": "12.39.0", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", - "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-13.0.0.tgz", + "integrity": "sha512-7DnN7TmbLcYXcG4RVadXIihWlyuM9afoUww8Y5Agg431kGKiuL2/OMyP4mJ5wLz+pvN3t5ySClLOaVXJ+wekRQ==", "license": "MIT" }, "node_modules/ms": { @@ -6543,9 +5927,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -6596,9 +5980,9 @@ "optional": true }, "node_modules/node-releases": { - "version": "2.0.52", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz", - "integrity": "sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "license": "MIT", "engines": { "node": ">=18" @@ -6608,6 +5992,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6639,6 +6024,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -6755,12 +6141,6 @@ "quickjs-wasi": "^2.2.0" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -6829,6 +6209,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6875,9 +6256,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "devOptional": true, "license": "MIT", "engines": { @@ -6934,9 +6315,9 @@ } }, "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "dev": true, "funding": [ { @@ -6954,7 +6335,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7026,9 +6407,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", - "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.5.tgz", + "integrity": "sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==", "dev": true, "license": "MIT", "dependencies": { @@ -7057,12 +6438,6 @@ "renderkid": "^3.0.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -7181,18 +6556,18 @@ } }, "node_modules/puppeteer": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-25.5.0.tgz", - "integrity": "sha512-qpp73xblxNr+bF0nSXTodM3v+zcK5IPo/GkjLsdUqRf/qpLJp/1KxBUbstoMMnwnPw9xD6OMei8kmYf6CLWfGw==", + "version": "25.9.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-25.9.0.tgz", + "integrity": "sha512-2JqQszD2pyDTpIvBH1ZCXdrHgENVNdJIeOM6asbwHRgWknFiaLd1gNB91w/B/0hQHNpafkpxa90lPpBaJM87Hw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "3.1.0", + "@puppeteer/browsers": "3.2.1", "chromium-bidi": "17.0.2", - "devtools-protocol": "0.0.1653615", + "devtools-protocol": "0.0.1666840", "lilconfig": "^3.1.3", - "puppeteer-core": "25.5.0", + "puppeteer-core": "25.9.0", "typed-query-selector": "^2.12.2" }, "bin": { @@ -7203,18 +6578,18 @@ } }, "node_modules/puppeteer-core": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.5.0.tgz", - "integrity": "sha512-XPNT0dQJtphqQ4I29zxlG4IIPbg1iEHAQKWuQgtMJGXjACV77pZSmJvDi51IIIfd+DTKICcopJwUx4upVQ4XbA==", + "version": "25.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.9.0.tgz", + "integrity": "sha512-U61rCwSMha62CA/Opy6tCx2Fx+ck7ouiKnbpEApzSoLYMoEu9F71nuFpHL55vmIt33/GYm6eKZVhH2ev0nAIeg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "3.1.0", + "@puppeteer/browsers": "3.2.1", "chromium-bidi": "17.0.2", - "devtools-protocol": "0.0.1653615", + "devtools-protocol": "0.0.1666840", "typed-query-selector": "^2.12.2", "webdriver-bidi-protocol": "0.4.2", - "ws": "^8.21.1" + "ws": "^8.21.3" }, "engines": { "node": ">=22.12.0" @@ -7292,6 +6667,15 @@ } } }, + "node_modules/react-redux/node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/react-redux/node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -7342,54 +6726,10 @@ "dev": true, "license": "MIT" }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -7420,6 +6760,15 @@ "@babel/runtime": "^7.9.2" } }, + "node_modules/redux/node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -7578,6 +6927,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -7586,30 +6936,10 @@ "rimraf": "bin.js" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/sass": { - "version": "1.102.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.102.0.tgz", - "integrity": "sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==", + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.103.1.tgz", + "integrity": "sha512-9icZURbP51S6S0QGoyaeqk9uB06GNWxsFYWfH5RgpFgqK5FA8tJcM3AdVxrZEVJ7dz+L87nG95gBKf4VuaMHGw==", "license": "MIT", "dependencies": { "chokidar": "^5.0.0", @@ -7675,18 +7005,6 @@ "node": ">=11.0.0" } }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -7727,21 +7045,15 @@ } }, "node_modules/serialize-javascript": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.7.tgz", - "integrity": "sha512-YAy8Od6KV+uuwUuU50np8fGB/Aues6Y0nAhA9y/hId74PlKUcme4pXcBD46NWKr1Q4osN/iseZ17YqO1XfmI8g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.0.tgz", + "integrity": "sha512-RNEqWOyhhUQYN9V1GfHwu9AR/g+NTciH6Z5u3/no6X3/w+04J2lVDL+svFQVXgXrEGBMG2puMVN3gq2SNGuTGw==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=20.0.0" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -7922,15 +7234,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-width": { "version": "8.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", @@ -7949,9 +7252,9 @@ } }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -8036,16 +7339,19 @@ } }, "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.1.0.tgz", + "integrity": "sha512-bwLf38YmY+TDYHJw1Ex0Co8c4yeXuJAo8YnXGZrscxrvYoVVIvLeniEkV1Ks/54VteMnL4FtyN1+P+TZJdUPmQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8" + } }, "node_modules/svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.3.tgz", - "integrity": "sha512-5EZD0pafXX6PphdwOGCiVLDSaV1xyuQao2blHajHLsPxr07q4mmEjdtXEWgG07ae2mIz8Ex2CDXNCTiXhy3Khw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.4.tgz", + "integrity": "sha512-2GJ4h3rl13qYTdwllaK6QlL8tG+UrM8626V2Ylcd/yBUv2Y/EwLsYisVV6UDCRmlk+C74G8nMpxJCk0RWPdDCw==", "dev": true, "license": "MIT", "dependencies": { @@ -8093,22 +7399,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tcp-port-used": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.3.tgz", @@ -8145,10 +7435,32 @@ "dev": true, "license": "MIT" }, + "node_modules/temporal-polyfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-1.0.4.tgz", + "integrity": "sha512-MLEU0qOD2uXlz24oINNtdLZQl8RgmMxSnRtKEGZGGetTJjlRwQJjk+VsJ4EREaUoiaTb8NJOcUiKtoAiWn9EBg==", + "license": "MIT", + "dependencies": { + "temporal-spec": "1.0.1", + "temporal-utils": "1.0.2" + } + }, + "node_modules/temporal-spec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-1.0.1.tgz", + "integrity": "sha512-wxVoanmDeavXie1vu2JaQ3WIc3JZnWAOYFBsJyATaVsXsycKYUflGsyBmrRSnoCpZJpwPyr38VpgSUlQ8CbFxg==", + "license": "Apache-2.0" + }, + "node_modules/temporal-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/temporal-utils/-/temporal-utils-1.0.2.tgz", + "integrity": "sha512-1B8Dl4KzrOvsNUlpoWGno2VLQlxroLjDgc5NBjVC9ax9ymdo+ezfyvhyjEMx+IVfhINr6CIG2gcnlP95iRrybQ==", + "license": "MIT" + }, "node_modules/terser": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.1.tgz", - "integrity": "sha512-7A2xlQ5EnGT8KPA92dUh6RbRYTVw8hEaEN9L1K68l4UOXFuV511NnAqObGoRqGOQofQcMypisu1s3xawCEHrvA==", + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -8251,26 +7563,12 @@ "version": "0.2.7", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.14" } }, - "node_modules/toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", - "license": "MIT" - }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "license": "MIT/X11", - "engines": { - "node": "*" - } - }, "node_modules/ts-loader": { "version": "9.6.2", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.6.2.tgz", @@ -8416,9 +7714,9 @@ } }, "node_modules/tslint/node_modules/js-yaml": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", - "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, "license": "MIT", "dependencies": { @@ -8550,58 +7848,10 @@ "node": ">=4" } }, - "node_modules/unzipper": { - "version": "0.10.14", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", - "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", - "license": "MIT", - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "node_modules/unzipper/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/unzipper/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/unzipper/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "funding": [ { "type": "opencollective", @@ -8766,6 +8016,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, "license": "MIT" }, "node_modules/utila": { @@ -8775,19 +8026,6 @@ "dev": true, "license": "MIT" }, - "node_modules/uuid": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", - "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, "node_modules/watchpack": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", @@ -8828,9 +8066,9 @@ "license": "MPL-2.0" }, "node_modules/webpack": { - "version": "5.109.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz", - "integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==", + "version": "5.110.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.1.tgz", + "integrity": "sha512-gInQB+jxXxgnZyvPwuzT5NGQmECDqeu85oxcrjinrYHqPoBex0hCAN2SFTJVyPVrK0Pq9E44VFP+e89fAc10/w==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", @@ -8843,11 +8081,10 @@ "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.24.4", "es-module-lexer": "^2.1.0", - "eslint-scope": "5.1.1", "events": "^3.2.0", "graceful-fs": "^4.2.11", "mime-db": "^1.54.0", - "minimizer-webpack-plugin": "^5.6.1", + "minimizer-webpack-plugin": "^5.7.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", @@ -9053,9 +8290,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -9116,12 +8353,25 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC" }, + "node_modules/write-excel-file": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/write-excel-file/-/write-excel-file-4.1.1.tgz", + "integrity": "sha512-MUnCnNtQrcZek832ZcU24uU0rSphFmKPD1DvIjXOlygVb93CV7Tme6H3jUTkxsMmjB2W7HIzERzjqTi5kui71A==", + "license": "MIT", + "dependencies": { + "fflate": "^0.8.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ws": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz", - "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { @@ -9140,12 +8390,6 @@ } } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "license": "MIT" - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -9201,41 +8445,6 @@ "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "license": "MIT", - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", diff --git a/accessibility-checker-extension/package.json b/accessibility-checker-extension/package.json index 0dc2509b6..cbe4eed8e 100644 --- a/accessibility-checker-extension/package.json +++ b/accessibility-checker-extension/package.json @@ -20,7 +20,7 @@ "@carbon/react": "^1.72.0", "@carbon/themes": "^11.17.0", "dotenv-webpack": "^7.0.3", - "exceljs": "^4.4.0", + "write-excel-file": "^4.1.1", "markdown-to-jsx": "^7.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/accessibility-checker-extension/preprocess.js b/accessibility-checker-extension/preprocess.js index d5cb92bbe..4c0d19f6f 100644 --- a/accessibility-checker-extension/preprocess.js +++ b/accessibility-checker-extension/preprocess.js @@ -1,22 +1 @@ -const { exec } = require("child_process"); - -function myExec(cmd) { - return new Promise((resolve, reject) => { - exec(cmd, (error, stdout, stderr) => { - if (error) { - reject(error.message); - return; - } - if (stderr) { - reject(stderr); - return; - } - resolve(stdout); - }); - }); -} - -(async () => { - await myExec(`sed -i'.old' -e "s/[\\"|']use strict[\\"|']//g" ./node_modules/exceljs/dist/exceljs.min.js`); - await myExec(`sed -i'.old' -e "s/[\\"|']use strict[\\"|']//g" ./node_modules/exceljs/dist/exceljs.js`); -})() \ No newline at end of file +// No preprocessing needed — exceljs has been replaced with write-excel-file diff --git a/accessibility-checker-extension/test/package-lock.json b/accessibility-checker-extension/test/package-lock.json index 7bb791e8f..95d294279 100644 --- a/accessibility-checker-extension/test/package-lock.json +++ b/accessibility-checker-extension/test/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "See LICENCSE.md", "dependencies": { - "exceljs": "^4.4.0", + "read-excel-file": "^9.3.10", "ts-node": "^10.9.2" }, "devDependencies": { @@ -309,9 +309,9 @@ } }, "node_modules/@cucumber/messages": { - "version": "34.2.0", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-34.2.0.tgz", - "integrity": "sha512-6X6T1TApmbQNqxC0Oh3GcnLU+gfE5fp+cEXE/ml6+Ldx76Q6BDmkgM5vagSSDXP+vetPV2Fb0kWVeP7QIR6+Aw==", + "version": "34.2.1", + "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-34.2.1.tgz", + "integrity": "sha512-aj2iCAG9ZOpMVcMxcgShifv5fbR96b7SMgdWcPXXh2QbFp7OEcAnQ5MC5YfWUDSDasmw7FU5NJEsOrXdTQOU1A==", "dev": true, "license": "MIT", "peer": true @@ -354,47 +354,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@fast-csv/format": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", - "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isboolean": "^3.0.3", - "lodash.isequal": "^4.5.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0" - } - }, - "node_modules/@fast-csv/format/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "license": "MIT" - }, - "node_modules/@fast-csv/parse": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", - "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.groupby": "^4.6.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0", - "lodash.isundefined": "^3.0.1", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/@fast-csv/parse/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "license": "MIT" - }, "node_modules/@ibm/telemetry-js": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@ibm/telemetry-js/-/telemetry-js-1.11.0.tgz", @@ -458,9 +417,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -485,13 +444,13 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.1.0.tgz", - "integrity": "sha512-RDLpio3fH/qrj5k4DVY6eyiN8tCS0Zovd/6jW//n605oeqkWcUjn+3k+9ZtZBnbwMpsu0F7xDIiKXvVmG5c5Bw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.2.1.tgz", + "integrity": "sha512-KDz+3qDRdBAlRlMjmKyj6dEs33YHTk/xRHEENSXq6TNnhgoU15ruSHtEBeVF6OZ9tBDY55Se4P0nFMNsipzU9A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "modern-tar": "^0.7.6", + "modern-tar": "^0.8.0", "yargs": "^18.0.0" }, "bin": { @@ -531,9 +490,9 @@ "license": "MIT" }, "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", "license": "MIT" }, "node_modules/@tsconfig/node12": { @@ -562,9 +521,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.1.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", - "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz", + "integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==", "license": "MIT", "peer": true, "dependencies": { @@ -586,9 +545,9 @@ "license": "MIT" }, "node_modules/accessibility-checker": { - "version": "4.0.29", - "resolved": "https://registry.npmjs.org/accessibility-checker/-/accessibility-checker-4.0.29.tgz", - "integrity": "sha512-7HFBcLNaN2ABkKrVxFHJX1Dh+3oC1sxMLMkoI3Qnz+UBZBXqaUcRujzYs+/j7i4ZGoAxZWLo96SqDE9Y4t1VUA==", + "version": "4.0.31", + "resolved": "https://registry.npmjs.org/accessibility-checker/-/accessibility-checker-4.0.31.tgz", + "integrity": "sha512-MXMaFXbRGEM/7Y1LBMq6jbHqPqkSfPKtIEXfjz9eclEjxk9FR/vug00oFiZj+jXyOR5jENLOYIrcqDwPU0ShFw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -636,13 +595,13 @@ } }, "node_modules/adm-zip": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", - "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", + "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0" + "node": ">=14.0" } }, "node_modules/agent-base": { @@ -688,118 +647,6 @@ "dev": true, "license": "MIT" }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "license": "MIT", - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/archiver-utils/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/archiver-utils/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -848,12 +695,6 @@ "node": ">=4" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -862,9 +703,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "dev": true, "license": "MIT", "dependencies": { @@ -878,26 +719,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "dev": true, "license": "MIT" }, "node_modules/basic-ftp": { @@ -910,87 +732,16 @@ "node": ">=10.0.0" } }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "license": "Unlicense", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "license": "MIT", - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", - "license": "MIT" - }, "node_modules/brace-expansion": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -998,23 +749,6 @@ "dev": true, "license": "MIT" }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -1058,18 +792,6 @@ "node": ">=18" } }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "license": "MIT/X11", - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1127,16 +849,16 @@ } }, "node_modules/chromedriver": { - "version": "151.0.2", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-151.0.2.tgz", - "integrity": "sha512-p2NI0qrBSpoksa9S4lxqpML28I1U1oMtNPyvbjiMlBB+JOn9qRQC/cuiAWPf36lAdsYgrqhQczb12UH2he04MQ==", + "version": "152.0.2", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-152.0.2.tgz", + "integrity": "sha512-w/trjzSjQC8vHHwl4e+WXBGPRN3XnrsY14q/FdxCY8GtTUIlB+wH1gn/Kz3CHpdmbsouUEGal6E8bjEEz72pZg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@testim/chrome-version": "^1.1.4", - "adm-zip": "^0.5.18", - "axios": "^1.18.1", + "adm-zip": "^0.6.0", + "axios": "^1.19.0", "compare-versions": "^6.1.1", "proxy-agent": "^8.0.2", "proxy-from-env": "^2.1.0", @@ -1310,58 +1032,6 @@ "dev": true, "license": "MIT" }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "license": "MIT", - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -1393,12 +1063,6 @@ "node": ">= 20" } }, - "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", - "license": "MIT" - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1463,9 +1127,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1653615", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1653615.tgz", - "integrity": "sha512-pGVkY3T/qXxAp2nFPodwYqOevk6ncNMSmvL8QfRCx5ZWGd6Vor7AFNmyaA8Zs6uJyP1QAfjuLandCgvSix1BNA==", + "version": "0.0.1666840", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1666840.tgz", + "integrity": "sha512-gCcO42XCHKEs7Ag0S7aGYsnJ7hlgrO3qderYqeiY0Eqk+0GFfuvT13IA0hHreJTa2KCdDVyGMeOhdMNmrrTjVg==", "dev": true, "license": "BSD-3-Clause" }, @@ -1493,45 +1157,6 @@ "node": ">= 0.4" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "license": "BSD-3-Clause", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexer2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1546,15 +1171,6 @@ "dev": true, "license": "MIT" }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/error-stack-parser": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", @@ -1690,38 +1306,11 @@ "node": ">=0.10.0" } }, - "node_modules/exceljs": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", - "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", - "license": "MIT", - "dependencies": { - "archiver": "^5.0.0", - "dayjs": "^1.8.34", - "fast-csv": "^4.3.1", - "jszip": "^3.10.1", - "readable-stream": "^3.6.0", - "saxes": "^5.0.1", - "tmp": "^0.2.0", - "unzipper": "^0.10.11", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/fast-csv": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", - "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", - "license": "MIT", - "dependencies": { - "@fast-csv/format": "4.3.5", - "@fast-csv/parse": "4.3.6" - }, - "engines": { - "node": ">=10.0.0" - } + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT" }, "node_modules/figures": { "version": "3.2.0", @@ -1807,46 +1396,6 @@ "node": ">= 6" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fstream/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2108,32 +1657,6 @@ "node": ">= 6" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -2157,23 +1680,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, "node_modules/ini": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", @@ -2185,9 +1691,9 @@ } }, "node_modules/ip-address": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz", - "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", + "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", "dev": true, "license": "MIT", "engines": { @@ -2276,12 +1782,6 @@ "node": ">=v0.10.0" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2313,9 +1813,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -2335,48 +1835,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/knuth-shuffle-seeded": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", @@ -2387,57 +1845,6 @@ "seed-random": "~2.2.0" } }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "license": "MIT", - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -2451,79 +1858,6 @@ "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", - "license": "ISC" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "license": "MIT" - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "license": "MIT" - }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "license": "MIT" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "license": "MIT" - }, - "node_modules/lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "license": "MIT" - }, - "node_modules/lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", - "license": "MIT" - }, - "node_modules/lodash.isnil": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", - "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT" - }, - "node_modules/lodash.isundefined": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", - "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2545,18 +1879,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "license": "MIT" - }, "node_modules/loupe": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", @@ -2666,15 +1988,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", @@ -2709,9 +2022,9 @@ } }, "node_modules/modern-tar": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.7.tgz", - "integrity": "sha512-t9VmxaqrmANnEOBhpSDI6HD192Ge48k8vmWqQQL7hSFEqHEYwZbbsu49+aKLWZeRvFs3j1pMhXOqqF4kPlvjkQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.8.4.tgz", + "integrity": "sha512-gN54ddmyzEg10orwZ2u4OOv+bjpMWdIl5jIkodK97bMq8QBSL5c0D7YX0lT1Ooz+99S7+PvFbnxzdjgHo1r41g==", "dev": true, "license": "MIT", "engines": { @@ -2758,6 +2071,12 @@ "tslib": "^2.0.3" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -2773,15 +2092,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2792,15 +2102,6 @@ "node": ">=0.10.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/pac-proxy-agent": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-9.1.0.tgz", @@ -2883,12 +2184,6 @@ "node": ">=0.10.0" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, "node_modules/parse-json": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", @@ -2907,15 +2202,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2960,12 +2246,6 @@ "dev": true, "license": "ISC" }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -3067,18 +2347,18 @@ } }, "node_modules/puppeteer": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-25.5.0.tgz", - "integrity": "sha512-qpp73xblxNr+bF0nSXTodM3v+zcK5IPo/GkjLsdUqRf/qpLJp/1KxBUbstoMMnwnPw9xD6OMei8kmYf6CLWfGw==", + "version": "25.9.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-25.9.0.tgz", + "integrity": "sha512-2JqQszD2pyDTpIvBH1ZCXdrHgENVNdJIeOM6asbwHRgWknFiaLd1gNB91w/B/0hQHNpafkpxa90lPpBaJM87Hw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "3.1.0", + "@puppeteer/browsers": "3.2.1", "chromium-bidi": "17.0.2", - "devtools-protocol": "0.0.1653615", + "devtools-protocol": "0.0.1666840", "lilconfig": "^3.1.3", - "puppeteer-core": "25.5.0", + "puppeteer-core": "25.9.0", "typed-query-selector": "^2.12.2" }, "bin": { @@ -3089,18 +2369,18 @@ } }, "node_modules/puppeteer-core": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.5.0.tgz", - "integrity": "sha512-XPNT0dQJtphqQ4I29zxlG4IIPbg1iEHAQKWuQgtMJGXjACV77pZSmJvDi51IIIfd+DTKICcopJwUx4upVQ4XbA==", + "version": "25.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.9.0.tgz", + "integrity": "sha512-U61rCwSMha62CA/Opy6tCx2Fx+ck7ouiKnbpEApzSoLYMoEu9F71nuFpHL55vmIt33/GYm6eKZVhH2ev0nAIeg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "3.1.0", + "@puppeteer/browsers": "3.2.1", "chromium-bidi": "17.0.2", - "devtools-protocol": "0.0.1653615", + "devtools-protocol": "0.0.1666840", "typed-query-selector": "^2.12.2", "webdriver-bidi-protocol": "0.4.2", - "ws": "^8.21.1" + "ws": "^8.21.3" }, "engines": { "node": ">=22.12.0" @@ -3113,6 +2393,21 @@ "dev": true, "license": "MIT" }, + "node_modules/read-excel-file": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/read-excel-file/-/read-excel-file-9.3.10.tgz", + "integrity": "sha512-zFcBdzunLCGBmLRT4Q3mLPJnhKPAXXfGAZ83feODlEqX2aRUbgF1h/n2oY0UF7I8tVwnJNRas6fTRD5veDUs+g==", + "license": "MIT", + "dependencies": { + "fflate": "^0.8.3", + "saxen": "^11.1.0", + "unzipper-esm": "^0.13.3", + "worker-f": "^0.1.12" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/read-package-up": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", @@ -3151,41 +2446,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", @@ -3223,92 +2483,13 @@ "node": ">=0.10" } }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "node_modules/saxen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/saxen/-/saxen-11.1.1.tgz", + "integrity": "sha512-J4BkmJFaM7VgE7pgkFGsNEcqqM3h7+Mz80vfLWFhx7uNOCOXIu6LLjQHYWNejdst3pf/3JUaBIG9+pkk1umlow==", "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, "engines": { - "node": ">=10" + "node": ">= 20.12" } }, "node_modules/seed-random": { @@ -3331,12 +2512,6 @@ "node": ">=10" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3488,15 +2663,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -3625,9 +2791,9 @@ } }, "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -3653,22 +2819,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tcp-port-used": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.3.tgz", @@ -3735,15 +2885,6 @@ "dev": true, "license": "MIT" }, - "node_modules/tmp": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", - "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", @@ -3751,15 +2892,6 @@ "dev": true, "license": "MIT" }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "license": "MIT/X11", - "engines": { - "node": "*" - } - }, "node_modules/ts-dedent": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", @@ -3873,52 +3005,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unzipper": { - "version": "0.10.14", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", - "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "node_modules/unzipper-esm": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/unzipper-esm/-/unzipper-esm-0.13.3.tgz", + "integrity": "sha512-LUO6VZ6fCzkDbdMev0/fOhoIeVGKaOkTIOoYxVLE0SQjfvmAHK+oywl7lfhloSZIsdGJ25mJ18Mtd9CyTASjrA==", "license": "MIT", "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "node_modules/unzipper/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/unzipper/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/unzipper/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" + "node-int64": "^0.4.0" + }, + "engines": { + "node": ">=8.0.0" } }, "node_modules/upper-case-first": { @@ -3938,16 +3035,11 @@ "dev": true, "license": "MIT" }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, "node_modules/uuid": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", - "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", + "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", + "dev": true, "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -3997,6 +3089,15 @@ "node": ">= 8" } }, + "node_modules/worker-f": { + "version": "0.1.20", + "resolved": "https://registry.npmjs.org/worker-f/-/worker-f-0.1.20.tgz", + "integrity": "sha512-7z5K5z4x++FykhpDTfriT/dOu7CmSap9BBv38DVFU3CD38obopq+DoFH75yBV3butpGm+OeqR9BKdSvYJSnUfQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -4111,16 +3212,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, "node_modules/ws": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz", - "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { @@ -4149,12 +3244,6 @@ "node": ">=8.0" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "license": "MIT" - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -4261,84 +3350,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "license": "MIT", - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/zip-stream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/zip-stream/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", diff --git a/accessibility-checker-extension/test/package.json b/accessibility-checker-extension/test/package.json index 79a462e4e..d901ef2f6 100644 --- a/accessibility-checker-extension/test/package.json +++ b/accessibility-checker-extension/test/package.json @@ -19,7 +19,7 @@ "typescript": "^5.8.3" }, "dependencies": { - "exceljs": "^4.4.0", + "read-excel-file": "^9.3.10", "ts-node": "^10.9.2" }, "overrides": { diff --git a/accessibility-checker-extension/test/support/steps/steps_excel.ts b/accessibility-checker-extension/test/support/steps/steps_excel.ts index 730206b04..8707822fe 100644 --- a/accessibility-checker-extension/test/support/steps/steps_excel.ts +++ b/accessibility-checker-extension/test/support/steps/steps_excel.ts @@ -1,22 +1,29 @@ import {Given, Then} from '@cucumber/cucumber'; -import { Workbook } from 'exceljs'; +import readExcelFile from 'read-excel-file/node'; import { join } from 'path'; import { PupUtil } from '../util/pup'; import { strict as assert } from "assert"; Given("excel file {string}", async function(filename: string) { - const workbook = new Workbook(); - await workbook.xlsx.readFile(join(PupUtil.getTempDownloadFolder(), filename)); - this.excelFile = workbook; + const filePath = join(PupUtil.getTempDownloadFolder(), filename); + const sheets = await readExcelFile(filePath); + this.excelFile = sheets; }); Then ("Excel Sheet {string} Cell {string} is {string}", async function(sheetStr: string, cellStr: string, txt: string) { - let workbook: Workbook = this.excelFile; - let sheet = workbook.getWorksheet(sheetStr); - if (!sheet) { - assert.fail("Sheet does not exist"); - } else { - let cell = sheet.getCell(cellStr); - assert.strictEqual(cell.text, txt); + // read-excel-file returns sheets as an array; we need to find by sheet name + // re-read to get named sheets + const filePath = join(PupUtil.getTempDownloadFolder(), this.excelFileName); + const allSheets = await readExcelFile(filePath); + // Find the sheet with matching name — readExcelFile returns array of { sheet, data } + const sheetObj = allSheets.find((s: any) => s.sheet === sheetStr); + if (!sheetObj) { + assert.fail(`Sheet "${sheetStr}" does not exist`); } -}); \ No newline at end of file + // Parse cell reference like "A1", "B3", etc. + const col = cellStr.charCodeAt(0) - 65; // 'A' = 0 + const row = parseInt(cellStr.slice(1)) - 1; + const cellValue = sheetObj.data[row]?.[col]; + const cellText = cellValue != null ? String(cellValue) : ""; + assert.strictEqual(cellText, txt); +}); diff --git a/accessibility-checker/package.json b/accessibility-checker/package.json index 0ecd50e25..ab855803c 100644 --- a/accessibility-checker/package.json +++ b/accessibility-checker/package.json @@ -23,10 +23,10 @@ "node": ">=16" }, "peerDependencies": { - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } }, diff --git a/accessibility-checker/src/package.json b/accessibility-checker/src/package.json index bf8d28b4b..2b067e97b 100644 --- a/accessibility-checker/src/package.json +++ b/accessibility-checker/src/package.json @@ -33,10 +33,10 @@ "puppeteer": "^25.1.0" }, "peerDependencies": { - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } }, diff --git a/common/module/package-lock.json b/common/module/package-lock.json index 9747e002f..7e302aa83 100644 --- a/common/module/package-lock.json +++ b/common/module/package-lock.json @@ -24,10 +24,10 @@ "node": ">=16" }, "peerDependencies": { - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } } @@ -904,9 +904,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -949,9 +949,9 @@ } }, "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", "dev": true, "license": "MIT" }, @@ -1326,9 +1326,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", - "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1363,9 +1363,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", - "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", "dev": true, "funding": [ { @@ -1383,11 +1383,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.44", - "caniuse-lite": "^1.0.30001806", - "electron-to-chromium": "^1.5.393", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" @@ -1447,9 +1447,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "dev": true, "funding": [ { @@ -1702,9 +1702,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.400", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.400.tgz", - "integrity": "sha512-96EWDNjM59SYflgeV5Ylsf4EMiq1a25YjCnJH7cxn/AF2H3pILRweaUnoLax0yKHWdpOzY6JKEu45e8irqZIHA==", + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", "dev": true, "license": "ISC" }, @@ -2862,9 +2862,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", - "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, "license": "MIT", "dependencies": { @@ -3100,9 +3100,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.52", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz", - "integrity": "sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "dev": true, "license": "MIT", "engines": { @@ -3906,9 +3906,9 @@ "license": "MIT" }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "dev": true, "funding": [ { diff --git a/common/module/package.json b/common/module/package.json index 09b36bead..3a8adbdb7 100644 --- a/common/module/package.json +++ b/common/module/package.json @@ -23,10 +23,10 @@ "typescript": "^5.1.3" }, "peerDependencies": { - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } }, diff --git a/common/module/src/report/ACReporterXLSX.ts b/common/module/src/report/ACReporterXLSX.ts index 3db2c69ac..45ceaadfa 100644 --- a/common/module/src/report/ACReporterXLSX.ts +++ b/common/module/src/report/ACReporterXLSX.ts @@ -20,26 +20,25 @@ import { CompressedReport } from "../engine/IReport.js"; import { eRuleConfidence } from "../engine/IRule.js"; import { GenSummReturn, IReporter, ReporterManager } from "./ReporterManager.js"; -// Lazy load exceljs - will be null if not installed -let exceljsLoadPromise: Promise | null = null; -let exceljsWarningShown = false; - -function loadExcelJS(): Promise { - if (!exceljsLoadPromise) { - // Use dynamic import with a variable to avoid TypeScript checking the module at compile time - const moduleName = "exceljs"; - exceljsLoadPromise = import(/* webpackIgnore: true */ moduleName) - .then(module => module) - .catch(e => null); +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise: Promise | null = null; +let writeExcelWarningShown = false; + +function loadWriteExcel(): Promise { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = import(/* webpackIgnore: true */ moduleName) + .then(module => module.default ?? module) + .catch(() => null); } - return exceljsLoadPromise; + return writeExcelLoadPromise; } -function showExcelJSWarning() { - if (!exceljsWarningShown) { - exceljsWarningShown = true; - console.warn("Warning: exceljs is not installed. XLSX report generation is disabled."); - console.warn("To enable XLSX reports, install exceljs: npm install exceljs"); +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); } } @@ -58,6 +57,55 @@ function dropDupes(arr: T[]): T[] { } }) } + +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb: string): string { + if (!argb || argb.length < 6) return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} + +// Helper: cell with dark purple header style +function headerCell(value: string | number, columnSpan?: number): any { + const cell: any = { + value, + backgroundColor: "#403151", + color: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) cell.columnSpan = columnSpan; + return cell; +} + +// Helper: standard data cell +function dataCell(value: string | number | null, opts?: any): any { + return { + value, + fontFamily: "Calibri", + fontSize: 12, + color: "#000000", + ...opts + }; +} + +// Helper: bordered cell +function borderedCell(value: string | number | null, opts?: any): any { + return { + value, + fontFamily: "Calibri", + fontSize: 12, + color: "#000000", + borderColor: "#A6A6A6", + borderStyle: "thin", + ...opts + }; +} + export class ACReporterXLSX implements IReporter { public name(): string { return "xlsx"; @@ -89,7 +137,6 @@ export class ACReporterXLSX implements IReporter { policyInfo[ruleId].tkLevels.sort(); } - // const buffer: any = await workbook.xlsx.writeBuffer(); let startScan = new Date(storedReport.engineReport.summary.startScan); let reportFilename = `results_${startScan.toISOString().replace(/:/g,"-")}.xlsx`; if (config.outputFilenameTimestamp === false) { @@ -98,36 +145,31 @@ export class ACReporterXLSX implements IReporter { return { summaryPath: reportFilename, summary: async (filename?: string) => { - const ExcelJSModule = await loadExcelJS(); - if (!ExcelJSModule) { - showExcelJSWarning(); + const writeExcelFile = await loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); return; } - // @ts-ignore - const workbook = new ExcelJSModule.stream.xlsx.WorkbookWriter({ filename, useStyles: true }); -// const workbook = new ExcelJS.Workbook({ useStyles: true }); - ACReporterXLSX.createOverviewSheet(config, summaryData, workbook); - ACReporterXLSX.createScanSummarySheet(config, summaryData, workbook); - ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData, workbook); - ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData, workbook); - ACReporterXLSX.createDefinitionsSheet(workbook); - workbook.commit(); + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData), + ACReporterXLSX.createDefinitionsSheet(), + ]; + await writeExcelFile(sheets).toFile(filename); } } } - private static createOverviewSheet(config: IConfigInternal, compressedScans: CompressedReport[], workbook: any) { + private static createOverviewSheet(config: IConfigInternal, compressedScans: CompressedReport[]): any { let violations = 0; let needsReviews = 0; let recommendations = 0; let archived = 0; let totalIssues = 0; - let startScan = 0; - // BIG QUESTION: is report - // 1. for current scan (from menu) - // 2. all stored scans (from menu) - // 3. selected stored scans (from scan manager) + for (const compressedScan of compressedScans) { let storedScan = ReporterManager.uncompressReport(compressedScan) if (startScan === 0) startScan = storedScan.engineReport.summary.startScan; @@ -139,343 +181,174 @@ export class ACReporterXLSX implements IReporter { } totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; - const worksheet = workbook.addWorksheet("Overview"); - - // Report Title - worksheet.mergeCells('A1', "E1"); - - const titleRow = worksheet.getRow(1); - titleRow.height = 27; - - const cellA1 = worksheet.getCell('A1'); - cellA1.value = "Accessibility Scan Report"; - cellA1.alignment = { vertical: "middle", horizontal: "left" }; - cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - // what are column widths - can't get it till you set it - - const colWidthData = [ - { col: 'A', width: 15.1 }, - { col: 'B', width: 15.9 }, - { col: 'C', width: 16.23 }, - { col: 'D', width: 19.4 }, - ] - - for (let i = 0; i < 4; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } - - // note except for Report Date this is the same for all scans const rowData: Array<{ key1: string, key2: string }> = [ { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, - // {key1: 'Version:', key2: "chrome.runtime.getManifest().version"}, { key1: 'Version:', key2: config.toolID }, - //@ts-ignore - // {key1: 'Rule set:', key2: (theCurrentScan.ruleSet === "Latest Deployment") ? archives[1].name : theCurrentScan.ruleSet }, { key1: 'Rule set:', key2: config.ruleArchiveLabel }, { key1: 'Guidelines:', key2: config.policies.join(", ") }, - { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, // do we need to get actual date? - { key1: 'Scans:', key2: "" + compressedScans.length }, // *** NEED TO FIX FOR selected - // { key1: 'Pages:', key2: "" } + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, ]; - for (let idx = 0; idx < rowData.length; ++idx) { - worksheet.mergeCells(`B${idx + 2}`, `E${idx + 2}`); - - let i = idx + 2; - worksheet.getRow(i).height = 12; // results in a row height of 16 - worksheet.getRow(i).getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(1).alignment = { horizontal: "left" }; - worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" }; - // if (i == 7) { - // worksheet.getRow(i).getCell(1).alignment = { vertical: "top" }; - // worksheet.getRow(i).getCell(2).alignment = { wrapText: true }; - // } - - worksheet.getRow(i).getCell(1).value = rowData[i - 2].key1; worksheet.getRow(i).getCell(2).value = rowData[i - 2].key2; - } - - // Summary Title - worksheet.mergeCells('A11', "E11"); - - const summaryRow = worksheet.getRow(11); - summaryRow.height = 27; - - const cellA11 = worksheet.getCell('A11'); - cellA11.value = "Summary"; - cellA11.alignment = { vertical: "middle", horizontal: "left" }; - cellA11.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA11.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - // Scans info Headers - worksheet.getRow(12).height = 16; // actual height is - - const cellA12 = worksheet.getCell('A12'); cellA12.value = "Total issues"; - const cellB12 = worksheet.getCell('B12'); cellB12.value = "Violations"; - const cellC12 = worksheet.getCell('C12'); cellC12.value = "Needs review"; - const cellD12 = worksheet.getCell('D12'); cellD12.value = "Recommendations"; - const cellE12 = worksheet.getCell('E12'); cellE12.value = "Archived"; - - const cellObjects1 = [cellA12, cellB12, cellC12, cellD12, cellE12]; - - for (let i = 0; i < cellObjects1.length; i++) { - cellObjects1[i].alignment = { vertical: "middle", horizontal: "center" }; - if (i == 1 || i == 2 || i == 3 || i === 4) { - cellObjects1[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - } else { - cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - } - - // cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} }; - cellObjects1[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } - - cellA12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - cellB12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - cellC12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - cellD12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - - - // Scans info Values - worksheet.getRow(13).height = 27; // actual height is + const data: any[][] = []; - const cellA13 = worksheet.getCell('A13'); cellA13.value = totalIssues; - const cellB13 = worksheet.getCell('B13'); cellB13.value = violations; - const cellC13 = worksheet.getCell('C13'); cellC13.value = needsReviews; - const cellD13 = worksheet.getCell('D13'); cellD13.value = recommendations; - const cellE13 = worksheet.getCell('E13'); cellE13.value = archived; - - const cellObjects2 = [cellA13, cellB13, cellC13, cellD13, cellE13]; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); - for (let i = 0; i < cellObjects2.length; i++) { - cellObjects2[i].alignment = { vertical: "middle", horizontal: "center" }; - cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - cellObjects2[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, color: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); } - } - private static createScanSummarySheet(config: IConfigInternal, compressedScans: CompressedReport[], workbook: any) { + // Row 8: blank spacer + data.push([null]); - const worksheet = workbook.addWorksheet("Scan summary"); + // Row 9: blank spacer + data.push([null]); - // Scans info Headers - worksheet.getRow(1).height = 39; // actual height is 52 + // Row 10: blank spacer + data.push([null]); - const colWidthData = [ - { col: 'A', width: 27.0 }, - { col: 'B', width: 46.0 }, - { col: 'C', width: 20.17 }, - { col: 'D', width: 18.5 }, - { col: 'E', width: 17.17 }, - { col: 'F', width: 17.17 }, - { col: 'G', width: 17.17 }, - { col: 'H', width: 17.17 }, - { col: 'I', width: 17.17 }, - ] + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); - for (let i = 0; i < 9; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", color: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", color: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", color: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", color: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", color: "#000000" }), + ]); - const cellA1 = worksheet.getCell('A1'); cellA1.value = "Page title"; - const cellB1 = worksheet.getCell('B1'); cellB1.value = "Page url"; - const cellC1 = worksheet.getCell('C1'); cellC1.value = "Scan label"; - - const cellObjects1 = [cellA1, cellB1, cellC1]; - - for (let i = 0; i < cellObjects1.length; i++) { - cellObjects1[i].alignment = { vertical: "middle", horizontal: "left" }; - cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - cellObjects1[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); - const cellD1 = worksheet.getCell('D1'); cellD1.value = "Violations"; - const cellE1 = worksheet.getCell('E1'); cellE1.value = "Needs review"; - const cellF1 = worksheet.getCell('F1'); cellF1.value = "Recommendations"; - const cellG1 = worksheet.getCell('G1'); cellG1.value = "Archived"; - const cellH1 = worksheet.getCell('H1'); cellH1.value = "% elements without violations"; - const cellI1 = worksheet.getCell('I1'); cellI1.value = "% elements without violations or items to review"; - - const cellObjects2 = [cellD1, cellE1, cellF1, cellG1, cellH1, cellI1]; - - for (let i = 0; i < cellObjects2.length; i++) { - cellObjects2[i].alignment = { vertical: "middle", horizontal: "center", wrapText: true }; - if (i == 0 || i == 1 || i == 2 || i == 3) { - cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - } else { - cellObjects2[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - } + return { data, sheet: "Overview", columns }; + } - // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} }; - cellObjects2[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } + private static createScanSummarySheet(config: IConfigInternal, compressedScans: CompressedReport[]): any { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; - cellD1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - cellE1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - cellF1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - cellG1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFFFF' } }; - cellH1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - cellI1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; + const headerStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = { ...headerStyle, align: "center", wrap: true }; + + const data: any[][] = []; + + // Row 1: header row + data.push([ + { value: "Page title", ...headerStyle, align: "left" }, + { value: "Page url", ...headerStyle, align: "left" }, + { value: "Scan label", ...headerStyle, align: "left" }, + { value: "Violations", ...countHeaderStyle, backgroundColor: "#E4AAAF", color: "#000000" }, + { value: "Needs review", ...countHeaderStyle, backgroundColor: "#F4E08A", color: "#000000" }, + { value: "Recommendations", ...countHeaderStyle, backgroundColor: "#96A9D7", color: "#000000" }, + { value: "Archived", ...countHeaderStyle, backgroundColor: "#FFFFFF", color: "#000000" }, + { value: "% elements without violations", ...countHeaderStyle }, + { value: "% elements without violations or items to review", ...countHeaderStyle }, + ]); for (const compressedScan of compressedScans) { let storedScan = ReporterManager.uncompressReport(compressedScan); let counts = storedScan.engineReport.summary.counts; - let row = worksheet.addRow([ - storedScan.pageTitle, - storedScan.engineReport.summary.URL, - storedScan.label, - counts.violation, - counts.potentialviolation + counts.manual, - counts.recommendation + counts.potentialrecommendation, - counts.ignored, - (100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0), - (100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0), + const textStyle = { fontFamily: "Calibri", fontSize: 12, color: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = { ...textStyle, align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }; + data.push([ + { value: storedScan.pageTitle, ...textStyle, align: "left" }, + { value: storedScan.engineReport.summary.URL, ...textStyle, align: "left" }, + { value: storedScan.label, ...textStyle, align: "left" }, + { value: counts.violation, ...numStyle }, + { value: counts.potentialviolation + counts.manual, ...numStyle }, + { value: counts.recommendation + counts.potentialrecommendation, ...numStyle }, + { value: counts.ignored, ...numStyle }, + { value: parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)), ...numStyle }, + { value: parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)), ...numStyle }, ]); - row.height = 37; // actual height is - for (let i = 1; i < 4; i++) { - row.getCell(i).alignment = { vertical: "middle", horizontal: "left", wrapText: true }; - row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 }; - } - for (let i = 4; i < 10; i++) { - row.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true }; - row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 }; - // row.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - row.getCell(i).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } - row.commit(); } - worksheet.commit(); - } - private static buildIssueSummaryLevel(worksheet: any, fillColor: string, title: string, levelCount: number, levelrowValues: any) { - // Level 1 Violation title - const level1ViolationRow = worksheet.addRow(["", 0]); - level1ViolationRow.height = 18; // target is 21 - - const cellA6 = level1ViolationRow.getCell(1); - cellA6.value = ` ${title}`; - cellA6.alignment = { vertical: "middle", horizontal: "left" }; - cellA6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellA6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } }; - level1ViolationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; + return { data, sheet: "Scan summary", columns }; + } - const cellB6 = level1ViolationRow.getCell(2); - cellB6.value = levelCount; // total level violations - cellB6.alignment = { vertical: "middle", horizontal: "right" }; - cellB6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellB6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } }; - level1ViolationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; + private static buildIssueSummaryLevelRows(fillColor: string, textColor: string, title: string, levelCount: number, levelrowValues: { [key: string]: any }): any[][] { + const rows: any[][] = []; - // Level 1 Violation Rows + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, color: textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, color: textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); - // build rows - let rowArray: any = []; - // let row:any =[]; + // Individual issue message rows, sorted descending by count + const rowArray: [string, number][] = []; for (const property in levelrowValues) { - let row: any = [" " + `${property}`, parseInt(`${levelrowValues[property]}`) - ]; - rowArray.push(row); + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); } + rowArray.sort((a, b) => b[1] - a[1]); - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - for (const rowInfo of rowArray) { - const row = worksheet.addRow(rowInfo); - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - // row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - // row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.commit(); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); } + + return rows; } - private static buildIssueSummaryTKLevel(worksheet: any, title: string, levelCounts: number[], levelVrowValues: any, levelNRrowValues: any, levelRrowValues: any, levelArowValues: any) { - ///////////////////////////// - // build Level title - ///////////////////////////// - - const level1Row = worksheet.addRow(["", 0]); - level1Row.height = 27; // actual is 36 - - const cellA5 = level1Row.getCell(1); - cellA5.value = title; - cellA5.alignment = { vertical: "middle", horizontal: "left" }; - cellA5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - const cellB5 = level1Row.getCell(2); - cellB5.value = levelCounts[0]; // total Level 1 issues - cellB5.alignment = { vertical: "middle", horizontal: "right" }; - cellB5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellB5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFE4AAAF", "Violation", levelCounts[1], levelVrowValues); - ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFF4E08A", "Needs review", levelCounts[2], levelNRrowValues); - ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FF96A9D7", "Recommendation", levelCounts[3], levelRrowValues); + private static buildIssueSummaryTKLevelRows(title: string, levelCounts: number[], levelVrowValues: any, levelNRrowValues: any, levelRrowValues: any, levelArowValues: any): any[][] { + const rows: any[][] = []; + + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation",levelCounts[3], levelRrowValues)); if (levelCounts[4] > 0) { - ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFCCCCCC", "Archived", levelCounts[4], levelArowValues); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); } - } - private static createIssueSummarySheet(config: IConfigInternal, policyInfo: { [ruleId: string]: PolicyInfo }, compressedScans: CompressedReport[], workbook: any) { + return rows; + } + private static createIssueSummarySheet(config: IConfigInternal, policyInfo: { [ruleId: string]: PolicyInfo }, compressedScans: CompressedReport[]): any { let violations = 0; let needsReviews = 0; let recommendations = 0; @@ -491,51 +364,31 @@ export class ACReporterXLSX implements IReporter { } totalIssues = violations + needsReviews + recommendations; - // counts - let level1Counts = [0, 0, 0, 0, 0]; // level 1 total issues, violations, needs reviews, recommendations + let level1Counts = [0, 0, 0, 0, 0]; let level2Counts = [0, 0, 0, 0, 0]; let level3Counts = [0, 0, 0, 0, 0]; let level4Counts = [0, 0, 0, 0, 0]; let level1V: any = []; let level2V: any = []; let level3V: any = []; let level4V: any = [] let level1NR: any = []; let level2NR: any = []; let level3NR: any = []; let level4NR: any = []; let level1R: any = []; let level2R: any = []; let level3R: any = []; let level4R: any = []; - let level1A: any = []; let level2A: any = []; let level3A: any = []; let level4A: any = [] + let level1A: any = []; let level2A: any = []; let level3A: any = []; let level4A: any = []; + for (const compressedScan of compressedScans) { let scan = ReporterManager.uncompressReport(compressedScan); for (const issue of scan.engineReport.results) { if (!(issue.ruleId in policyInfo)) { - policyInfo[issue.ruleId] = { - tkLevels: [], - cps: [] - } + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] } } let levelCounts, levelV, levelNR, levelR, levelA; - const issuePolicyInfo = policyInfo[issue.ruleId]; if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_ONE)) { - levelCounts = level1Counts; - levelV = level1V; - levelNR = level1NR; - levelR = level1R; - levelA = level1A; + levelCounts = level1Counts; levelV = level1V; levelNR = level1NR; levelR = level1R; levelA = level1A; } else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_TWO)) { - levelCounts = level2Counts; - levelV = level2V; - levelNR = level2NR; - levelR = level2R; - levelA = level2A; + levelCounts = level2Counts; levelV = level2V; levelNR = level2NR; levelR = level2R; levelA = level2A; } else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_THREE)) { - levelCounts = level3Counts; - levelV = level3V; - levelNR = level3NR; - levelR = level3R; - levelA = level3A; + levelCounts = level3Counts; levelV = level3V; levelNR = level3NR; levelR = level3R; levelA = level3A; } else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_FOUR)) { - levelCounts = level4Counts; - levelV = level4V; - levelNR = level4NR; - levelR = level4R; - levelA = level4A; + levelCounts = level4Counts; levelV = level4V; levelNR = level4NR; levelR = level4R; levelA = level4A; } if (issue.value[1] !== eRuleConfidence.PASS) { ++levelCounts[0]; @@ -557,139 +410,78 @@ export class ACReporterXLSX implements IReporter { } // @ts-ignore - let level1VrowValues: { [index: string]: any } = this.countDuplicatesInArray(level1V); // note this returns an object + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); // @ts-ignore - let level1NRrowValues: { [index: string]: any } = this.countDuplicatesInArray(level1NR); + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); // @ts-ignore - let level1RrowValues: { [index: string]: any } = this.countDuplicatesInArray(level1R); + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); // @ts-ignore - let level1ArowValues: { [index: string]: any } = this.countDuplicatesInArray(level1A); - + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); // @ts-ignore - let level2VrowValues: { [index: string]: any } = this.countDuplicatesInArray(level2V); // note this returns an object + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); // @ts-ignore - let level2NRrowValues: { [index: string]: any } = this.countDuplicatesInArray(level2NR); + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); // @ts-ignore - let level2RrowValues: { [index: string]: any } = this.countDuplicatesInArray(level2R); + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); // @ts-ignore - let level2ArowValues: { [index: string]: any } = this.countDuplicatesInArray(level2A); - + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); // @ts-ignore - let level3VrowValues: { [index: string]: any } = this.countDuplicatesInArray(level3V); // note this returns an object + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); // @ts-ignore - let level3NRrowValues: { [index: string]: any } = this.countDuplicatesInArray(level3NR); + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); // @ts-ignore - let level3RrowValues: { [index: string]: any } = this.countDuplicatesInArray(level3R); + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); // @ts-ignore - let level3ArowValues: { [index: string]: any } = this.countDuplicatesInArray(level3A); - + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); // @ts-ignore - let level4VrowValues: { [index: string]: any } = this.countDuplicatesInArray(level4V); // note this returns an object + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); // @ts-ignore - let level4NRrowValues: { [index: string]: any } = this.countDuplicatesInArray(level4NR); + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); // @ts-ignore - let level4RrowValues: { [index: string]: any } = this.countDuplicatesInArray(level4R); + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); // @ts-ignore - let level4ArowValues: { [index: string]: any } = this.countDuplicatesInArray(level4A); - - - - const worksheet = workbook.addWorksheet("Issue summary"); - - // Approach: - // 1. sort by levels - // 2. for each level sort by V, NR and R - // 3. for each V, NR, and R in a level get issue dup counts - // 4. build the rows - - // build Issue summary title - worksheet.mergeCells('A1', "B1"); - - const titleRow = worksheet.getRow(1); - titleRow.height = 27; // actual is 36 + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); - const cellA1 = worksheet.getCell('A1'); - cellA1.value = "Issue summary"; - cellA1.alignment = { vertical: "middle", horizontal: "left" }; - cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - const colWidthData = [ - { col: 'A', width: 155.51 }, // note .84 added to actual width - { col: 'B', width: 21.16 }, - ] - - for (let i = 0; i < 2; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } - - // build Description title - worksheet.mergeCells('A2', "B2"); - - const descriptionRow = worksheet.getRow(2); - descriptionRow.height = 20.25; // actual is 27 - - const cellA2 = worksheet.getCell("A2"); - cellA2.value = " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first."; - cellA2.alignment = { vertical: "middle", horizontal: "left" }; - cellA2.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - // cellA2.fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFCCC0DA'} }; - - - - - // build Total issues found: title - // worksheet.mergeCells('A3', "B3"); - - const totalIssuesRow = worksheet.getRow(3); - totalIssuesRow.height = 27; // actual is 36 + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; - const cellA3 = worksheet.getCell("A3"); - cellA3.value = "Total issues found:"; - cellA3.alignment = { vertical: "middle", horizontal: "left" }; - cellA3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; + const data: any[][] = []; - const cellB3 = worksheet.getCell("B3"); - cellB3.value = totalIssues; - cellB3.alignment = { vertical: "middle", horizontal: "right" }; - cellB3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellB3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); - // build Number of issues title - const numberOfIssuesRow = worksheet.getRow(4); - numberOfIssuesRow.height = 20.25; // actual is 27 + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, color: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); - const cellA4 = worksheet.getCell("A4"); - // no value - cellA4.alignment = { vertical: "middle", horizontal: "left" }; - cellA4.border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFFFFFFF' } } - }; + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); - const cellB4 = worksheet.getCell("B4"); - cellB4.value = "Number of issues"; - cellB4.alignment = { vertical: "middle", horizontal: "right" }; - cellB4.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellB4.border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFFFFFFF' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); - ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues); - ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues); - ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues); - ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues); - worksheet.commit(); + return { data, sheet: "Issue summary", columns }; } - private static createIssuesSheet(config: IConfigInternal, policyInfo: { [ruleId: string]: PolicyInfo }, compressedScans: CompressedReport[], workbook: any) { + private static createIssuesSheet(config: IConfigInternal, policyInfo: { [ruleId: string]: PolicyInfo }, compressedScans: CompressedReport[]): any { const valueMap: { [key: string]: { [key2: string]: string } } = { "VIOLATION": { "POTENTIAL": "Needs review", @@ -711,249 +503,96 @@ export class ACReporterXLSX implements IReporter { } }; - const worksheet = workbook.addWorksheet("Issues"); + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + + const hStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", align: "center", alignVertical: "center", wrap: true, height: 24 }; + + const data: any[][] = []; + + // Header row + data.push([ + { value: "Page title", ...hStyle }, + { value: "Page URL", ...hStyle }, + { value: "Scan label", ...hStyle }, + { value: "Issue ID", ...hStyle }, + { value: "Issue type", ...hStyle }, + { value: "Toolkit level",...hStyle }, + { value: "Checkpoint", ...hStyle }, + { value: "WCAG level", ...hStyle }, + { value: "Rule", ...hStyle }, + { value: "Issue", ...hStyle }, + { value: "Element", ...hStyle }, + { value: "Code", ...hStyle }, + { value: "Xpath", ...hStyle }, + { value: "Help", ...hStyle }, + ]); - // build rows - let rowArray: any = []; for (const compressedScan of compressedScans) { let storedScan = ReporterManager.uncompressReport(compressedScan); for (const item of storedScan.engineReport.results) { if (!(item.ruleId in policyInfo)) { - policyInfo[item.ruleId] = { - tkLevels: [], - cps: [] - } + policyInfo[item.ruleId] = { tkLevels: [], cps: [] } } let polInfo = policyInfo[item.ruleId]; let cps = polInfo.cps.filter(cp => { let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes(""+item.reasonId))); return !!ruleInfo; - }) + }); let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); wcagLevels.sort(); let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); cpStrs.sort(); - let row = [ - storedScan.pageTitle, - storedScan.engineReport.summary.URL, - storedScan.label, - this.stringHash(item.ruleId + item.path.dom), - `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}`, - polInfo.tkLevels.join(", "), - cpStrs.join("; "), - wcagLevels.join(", "), - item.ruleId, - item.message.substring(0, 32767), //max ength for MS Excel 32767 characters - this.get_element(item.snippet), - item.snippet.substring(0, 32767), - item.path.dom, - item.help, - item.source - // engine_end_point + '/tools/help/' + item.ruleId - ] - - // let row = [myStoredData[i][0], myStoredData[i][1], storedScans[j].label, - // myStoredData[i][3], myStoredData[i][4], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][5], - // myStoredData[i][6], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][7], myStoredData[i][8], - // myStoredData[i][9], myStoredData[i][10], myStoredData[i][11], - // myStoredData[i][12], myStoredData[i][13] - // ]; - rowArray.push(row); - } - } - // column widths - const colWidthData: Array<{ - col: string, - width: number, - alignment: { - vertical: "middle", - horizontal: "left" | "center" | "fill" + const dStyle = { fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", height: 14 }; + data.push([ + { value: storedScan.pageTitle, ...dStyle, align: "left", alignVertical: "center" }, + { value: storedScan.engineReport.summary.URL, ...dStyle, align: "left", alignVertical: "center" }, + { value: storedScan.label, ...dStyle, align: "center", alignVertical: "center" }, + { value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom), ...dStyle, align: "left", alignVertical: "center" }, + { value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}`,...dStyle, align: "center", alignVertical: "center" }, + { value: polInfo.tkLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" }, + { value: cpStrs.join("; "), ...dStyle, align: "left", alignVertical: "center" }, + { value: wcagLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" }, + { value: item.ruleId, ...dStyle, align: "left", alignVertical: "center" }, + { value: item.message.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" }, + { value: ACReporterXLSX.get_element(item.snippet), ...dStyle, align: "center", alignVertical: "center" }, + { value: item.snippet.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" }, + { value: item.path.dom, ...dStyle, align: "left", alignVertical: "center" }, + { value: item.help, ...dStyle, align: "left", alignVertical: "center" }, + ]); } - }> = [ - { col: 'A', width: 18.0, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'B', width: 20.5, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'C', width: 21.0, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'D', width: 18.5, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'E', width: 17.0, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'F', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'G', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'H', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'I', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'J', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'K', width: 14.00, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'L', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'M', width: 43.00, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'N', width: 17.17, alignment: { vertical: "middle", horizontal: "fill" } }, - ] - - for (let i = 0; i < 14; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - worksheet.getColumn(colWidthData[i].col).alignment = colWidthData[i].alignment; } - - // add table to a sheet - let headRow = worksheet.addRow([ - "Page title", - "Page URL", - "Scan label", - "Issue ID", - "Issue type", - "Toolkit level", - "Checkpoint", - "WCAG level", - "Rule", - "Issue", - "Element", - "Code", - "Xpath", - "Help", - "" - ]); - // set font and alignment for the header cells - for (let i = 1; i < 15; i++) { - headRow.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true }; - headRow.getCell(i).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - headRow.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - headRow.getCell(i).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } - - // height for header row - headRow.height = 24; - - headRow.commit(); - for (const rowInfo of rowArray) { - const row = worksheet.addRow(rowInfo); - row.height = 14; - for (let j = 1; j <= 14; j++) { - row.getCell(j).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } - row.commit(); - } - for (const key in worksheet) { - if (typeof worksheet[key] === "function") { - console.log(key); - } - } - // worksheet.addTable({ - // name: 'MyTable', - // ref: 'A1', - // headerRow: true, - // // totalsRow: true, - // style: { - // theme: 'TableStyleMedium2', - // showRowStripes: true, - // }, - // columns: [ - // { name: 'Page title', filterButton: true }, - // { name: 'Page URL', filterButton: true }, - // { name: 'Scan label', filterButton: true }, - // { name: 'Issue ID', filterButton: true }, - // { name: 'Issue type', filterButton: true }, - // { name: 'Toolkit level', filterButton: true }, - // { name: 'Checkpoint', filterButton: true }, - // { name: 'WCAG level', filterButton: true }, - // { name: 'Rule', filterButton: true }, - // { name: 'Issue', filterButton: true }, - // { name: 'Element', filterButton: true }, - // { name: 'Code', filterButton: true }, - // { name: 'Xpath', filterButton: true }, - // { name: 'Help', filterButton: true }, - - // ], - // rows: rowArray - // }); - - // for (let i = 2; i <= rowArray.length + 1; i++) { - // worksheet.getRow(i).height = 14; - // for (let j = 1; j <= 14; j++) { - // worksheet.getRow(i).getCell(j).border = { - // top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - // } - // } - // worksheet.getRow(i).commit(); - // } - worksheet.commit(); + return { data, sheet: "Issues", columns }; } - private static createDefinitionsSheet(workbook: any) { - - const worksheet = workbook.addWorksheet("Definition of fields"); - - // "Definition of fields" title - worksheet.mergeCells('A1', "B1"); - - const titleRow = worksheet.getRow(1); - titleRow.height = 36; // actual is 48 - - titleRow.getCell(1).value = "Definition of fields"; - titleRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - titleRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: "20" }; - titleRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - const colWidthData = [ - { col: 'A', width: '41.51' }, // note .84 added to actual width - { col: 'B', width: '119.51' }, - ] - - for (let i = 0; i < 2; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } - - // blank row - worksheet.mergeCells('A2', "B2"); - const blankRow = worksheet.getRow(2); - blankRow.height = 12; // actual is 16 - - // "Scan summary and Issue summary" title - worksheet.mergeCells('A3', "B3"); - - const summaryRow = worksheet.getRow(3); - summaryRow.height = 20; // actual is 26.75 - - summaryRow.getCell(1).value = "Scan summary and Issue summary"; - summaryRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - summaryRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - summaryRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - // row 4 Field / Definition - const row4 = worksheet.getRow(4); - row4.height = 16; // actual is - - row4.getCell(1).value = "Field"; - row4.getCell(2).value = "Definition"; - row4.getCell(1).alignment = row4.getCell(2).alignment = { vertical: "middle", horizontal: "left" }; - row4.getCell(1).font = row4.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 }; - row4.getCell(1).fill = row4.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } }; - row4.getCell(1).border = row4.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // rows 5-13 + private static createDefinitionsSheet(): any { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; - // set row height for rows 5-13 - for (let i = 5; i < 14; i++) { - worksheet.getRow(i).height = 12; // results in a row height of 16 - } + const titleStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", color: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, color: "#000000", align: "left", height: 12 }; - let rowData = [ + const summaryRowData = [ { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, @@ -964,52 +603,7 @@ export class ACReporterXLSX implements IReporter { { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } ]; - for (let i = 5; i < rowData.length + 5; i++) { - worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" }; - - } - for (let i = 5; i < rowData.length + 5; i++) { - worksheet.getRow(i).getCell(1).value = rowData[i - 5].key1; worksheet.getRow(i).getCell(2).value = rowData[i - 5].key2; - } - - // "Scan summary and Issue summary" title - worksheet.mergeCells('A14', "B14"); - - const issuesRow = worksheet.getRow(14); - issuesRow.height = 20; // actual is 26.75 - - issuesRow.getCell(1).value = "Issues"; - issuesRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - issuesRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - issuesRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - // row 15 Field / Definition - const row15 = worksheet.getRow(15); - row15.height = 16; // actual is - - row15.getCell(1).value = "Field"; - row15.getCell(2).value = "Definition"; - row15.getCell(1).alignment = row15.getCell(2).alignment = { vertical: "middle", horizontal: "left" }; - row15.getCell(1).font = row15.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 }; - row15.getCell(1).fill = row15.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } }; - row15.getCell(1).border = row15.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // rows 16-28 - - // set row height for rows 16-28 - for (let i = 16; i < 29; i++) { - worksheet.getRow(i).height = 12; // results in a row height of 16 - } - - rowData = []; - - rowData = [ + const issuesRowData = [ { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, @@ -1025,23 +619,66 @@ export class ACReporterXLSX implements IReporter { { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, ]; - for (let i = 16; i < 29; i++) { - worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" }; + const data: any[][] = []; + + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + { value: "Definition of fields", ...titleStyle, height: 36, columnSpan: 2 }, + null + ]); + + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + + // Row 3: "Scan summary and Issue summary" section header + data.push([ + { value: "Scan summary and Issue summary", ...sectionStyle, height: 20, columnSpan: 2 }, + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + { value: "Field", ...subHeaderStyle, height: 16 }, + { value: "Definition", ...subHeaderStyle }, + ]); + + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + { value: row.key1, ...dataStyle }, + { value: row.key2, ...dataStyle }, + ]); } - for (let i = 16; i < 29; i++) { - worksheet.getRow(i).getCell(1).value = rowData[i - 16].key1; worksheet.getRow(i).getCell(2).value = rowData[i - 16].key2; + + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + + // Row 14: "Issues" section header + data.push([ + { value: "Issues", ...sectionStyle, height: 20, columnSpan: 2 }, + null + ]); + + // Row 15: "Field / Definition" subheader + data.push([ + { value: "Field", ...subHeaderStyle, height: 16 }, + { value: "Definition", ...subHeaderStyle }, + ]); + + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + { value: row.key1, ...dataStyle }, + { value: row.key2, ...dataStyle }, + ]); } - worksheet.commit(); + + return { data, sheet: "Definition of fields", columns }; } private static countDuplicatesInArray(array: []) { let count = {}; - // let result = []; - array.forEach(item => { - if (count[item]) { //@ts-ignore count[item] += 1 @@ -1053,21 +690,17 @@ export class ACReporterXLSX implements IReporter { return count; } - private static get_element(code: string) { - if (code) { const ind_s = code.indexOf(' '); const ind_br = code.indexOf('>'); return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br) } - return ''; } private static format_date(timestamp: string) { var date = new Date(timestamp); - return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + ("00" + date.getDate()).slice(-2) + "-" + ("00" + date.getHours()).slice(-2) + "-" + @@ -1079,15 +712,9 @@ export class ACReporterXLSX implements IReporter { private static stringHash(str) { var hash = 5381, i = str.length; - while (i) { hash = (hash * 33) ^ str.charCodeAt(--i); } - - /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed - * integers. Since we want the results to be always positive, convert the - * signed int to an unsigned by doing an unsigned bitshift. */ return hash >>> 0; } - } diff --git a/cypress-accessibility-checker/boilerplates/package-lock.json b/cypress-accessibility-checker/boilerplates/package-lock.json index 692e8dde1..7381a761b 100644 --- a/cypress-accessibility-checker/boilerplates/package-lock.json +++ b/cypress-accessibility-checker/boilerplates/package-lock.json @@ -209,9 +209,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", - "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, "license": "MIT", "dependencies": { @@ -444,9 +444,9 @@ } }, "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-3.0.0.tgz", + "integrity": "sha512-AmIAC+Wtm2AU8lGfTtHsw0Y9Qtftx2YXEEtiBP10xFUtMOA+sHHx6OAddyL52mUKh1vsXQ6/w1mVDptZCyUt4Q==", "dev": true, "funding": [ { @@ -550,9 +550,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "dev": true, "license": "MIT", "dependencies": { @@ -778,6 +778,27 @@ "node": ">= 0.8.0" } }, + "node_modules/chrome-remote-interface": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.3.tgz", + "integrity": "sha512-zNnn0prUL86Teru6UCAZ1yU1XeXljHl3gj7OrfPcarEfU62OUU4IujDPdTDW3dAWwRqN3ZMG/Chhkh2gPL/wiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "2.11.x", + "ws": "^7.2.0" + }, + "bin": { + "chrome-remote-interface": "bin/client.js" + } + }, + "node_modules/chrome-remote-interface/node_modules/commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true, + "license": "MIT" + }, "node_modules/ci-info": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", @@ -844,9 +865,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -1000,9 +1021,9 @@ } }, "node_modules/cypress": { - "version": "15.19.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.19.0.tgz", - "integrity": "sha512-kjy1u3SWlMRWS5qffH3U+bXx1PqPP7qwhIzEY3UtERcW2r/8zy5uk6uSwa75pYXJyYFVP1SO8mAn/avZUvUbfg==", + "version": "15.21.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.21.1.tgz", + "integrity": "sha512-ogHpHMj0XNlZA5MGzjg8SWHf0eMw9lTwVQRKjpcT1GzNTxNUjwnHA8YCG6nOJ8ThU+XZaUxJgpMYZnJ//8aDaw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1012,12 +1033,13 @@ "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "@types/tmp": "^0.2.3", - "arch": "^2.2.0", + "arch": "^3.0.0", "blob-util": "^2.0.2", "bluebird": "^3.7.2", "buffer": "^5.7.1", "cachedir": "^2.4.0", "chalk": "^4.1.0", + "chrome-remote-interface": "0.33.3", "ci-info": "^4.1.0", "cli-table3": "0.6.1", "commander": "^6.2.1", @@ -1043,7 +1065,6 @@ "systeminformation": "^5.31.1", "tmp": "~0.2.4", "tree-kill": "1.2.2", - "tslib": "1.14.1", "untildify": "^4.0.0", "yauzl": "^3.3.1" }, @@ -1055,9 +1076,9 @@ } }, "node_modules/cypress-accessibility-checker": { - "version": "4.0.29", - "resolved": "https://registry.npmjs.org/cypress-accessibility-checker/-/cypress-accessibility-checker-4.0.29.tgz", - "integrity": "sha512-mIFgMtyBeySkYb8RWcQPid+WFqHVYlpIpLjq8wpwMvsj10Yhio1MW8Z6KTAvbpqm+XFPZOvv9RjO5d2g7rJpgw==", + "version": "4.0.31", + "resolved": "https://registry.npmjs.org/cypress-accessibility-checker/-/cypress-accessibility-checker-4.0.31.tgz", + "integrity": "sha512-ZPMFDqzQTxdEGTyHmp+pufA0yot/AiNGYZjROF2Ed3RPH6ZLKfh1F3LuLlswN2qJZ4aAcieMuL6znd4yUxlgzw==", "dev": true, "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", @@ -1091,9 +1112,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "version": "1.11.23", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", "dev": true, "license": "MIT" }, @@ -1417,9 +1438,9 @@ } }, "node_modules/eslint/node_modules/js-yaml": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", - "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, "license": "MIT", "dependencies": { @@ -1641,9 +1662,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.6.tgz", + "integrity": "sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==", "dev": true, "funding": [ { @@ -2350,9 +2371,9 @@ "license": "MIT" }, "node_modules/joi": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.2.3.tgz", - "integrity": "sha512-N5A3KTWQpPWT4ExxxPlUx7WmykGXRzhNidWhV41d6Abu9YfI2NyWCJuxdPnslJCPWtbRpSVOWSnSS6GakLM/Rg==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.2.5.tgz", + "integrity": "sha512-+gEA7rLfaNWx9JzawWPrPetSZwT16NUqHtECDgjyAJreXcs4TM7tx2Pa+VVJJK0YHM83ybrVdaT6UekHH50FJQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2376,9 +2397,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -2594,9 +2615,9 @@ } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -3190,13 +3211,6 @@ "tslib": "^2.1.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3587,9 +3601,9 @@ } }, "node_modules/systeminformation": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.1.tgz", - "integrity": "sha512-DEN6ICHk3Tk0Uf/hrAHh7xlt7iL5CJFBtPZinA0H62DrGG/KPKqq/Nzj6lCXPS4Ay/sf/14zNnk9LpqKzBIc+w==", + "version": "5.33.5", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.5.tgz", + "integrity": "sha512-0v8l1CwFOAjfkv6ynpMrv3YGjH0M7PWCpZwusr8J1TEoQFPK7WXO6gbeAiandaWoh7vbMdnFtDqVotJVnLJtIg==", "dev": true, "license": "MIT", "os": [ @@ -3760,9 +3774,9 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -3962,9 +3976,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -4035,6 +4049,28 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yauzl": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", diff --git a/cypress-accessibility-checker/package-lock.json b/cypress-accessibility-checker/package-lock.json index bff585527..ea9f95cee 100644 --- a/cypress-accessibility-checker/package-lock.json +++ b/cypress-accessibility-checker/package-lock.json @@ -26,10 +26,10 @@ }, "peerDependencies": { "cypress": "^13.2.0 || ^15", - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } } @@ -315,9 +315,9 @@ "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "dev": true, "license": "ISC" }, @@ -416,9 +416,9 @@ } }, "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-3.0.0.tgz", + "integrity": "sha512-AmIAC+Wtm2AU8lGfTtHsw0Y9Qtftx2YXEEtiBP10xFUtMOA+sHHx6OAddyL52mUKh1vsXQ6/w1mVDptZCyUt4Q==", "dev": true, "funding": [ { @@ -510,9 +510,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", @@ -726,6 +726,27 @@ "node": ">= 0.8.0" } }, + "node_modules/chrome-remote-interface": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.3.tgz", + "integrity": "sha512-zNnn0prUL86Teru6UCAZ1yU1XeXljHl3gj7OrfPcarEfU62OUU4IujDPdTDW3dAWwRqN3ZMG/Chhkh2gPL/wiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "2.11.x", + "ws": "^7.2.0" + }, + "bin": { + "chrome-remote-interface": "bin/client.js" + } + }, + "node_modules/chrome-remote-interface/node_modules/commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true, + "license": "MIT" + }, "node_modules/ci-info": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", @@ -792,9 +813,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -947,9 +968,9 @@ } }, "node_modules/cypress": { - "version": "15.19.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.19.0.tgz", - "integrity": "sha512-kjy1u3SWlMRWS5qffH3U+bXx1PqPP7qwhIzEY3UtERcW2r/8zy5uk6uSwa75pYXJyYFVP1SO8mAn/avZUvUbfg==", + "version": "15.21.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.21.1.tgz", + "integrity": "sha512-ogHpHMj0XNlZA5MGzjg8SWHf0eMw9lTwVQRKjpcT1GzNTxNUjwnHA8YCG6nOJ8ThU+XZaUxJgpMYZnJ//8aDaw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -959,12 +980,13 @@ "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "@types/tmp": "^0.2.3", - "arch": "^2.2.0", + "arch": "^3.0.0", "blob-util": "^2.0.2", "bluebird": "^3.7.2", "buffer": "^5.7.1", "cachedir": "^2.4.0", "chalk": "^4.1.0", + "chrome-remote-interface": "0.33.3", "ci-info": "^4.1.0", "cli-table3": "0.6.1", "commander": "^6.2.1", @@ -990,7 +1012,6 @@ "systeminformation": "^5.31.1", "tmp": "~0.2.4", "tree-kill": "1.2.2", - "tslib": "1.14.1", "untildify": "^4.0.0", "yauzl": "^3.3.1" }, @@ -1022,9 +1043,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "version": "1.11.23", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", "dev": true, "license": "MIT" }, @@ -1464,9 +1485,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", + "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", "dev": true, "license": "ISC", "dependencies": { @@ -2199,9 +2220,9 @@ "license": "MIT" }, "node_modules/joi": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.2.3.tgz", - "integrity": "sha512-N5A3KTWQpPWT4ExxxPlUx7WmykGXRzhNidWhV41d6Abu9YfI2NyWCJuxdPnslJCPWtbRpSVOWSnSS6GakLM/Rg==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.2.5.tgz", + "integrity": "sha512-+gEA7rLfaNWx9JzawWPrPetSZwT16NUqHtECDgjyAJreXcs4TM7tx2Pa+VVJJK0YHM83ybrVdaT6UekHH50FJQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2218,9 +2239,9 @@ } }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -2444,9 +2465,9 @@ } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -3152,13 +3173,6 @@ "tslib": "^2.1.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3577,9 +3591,9 @@ } }, "node_modules/systeminformation": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.1.tgz", - "integrity": "sha512-DEN6ICHk3Tk0Uf/hrAHh7xlt7iL5CJFBtPZinA0H62DrGG/KPKqq/Nzj6lCXPS4Ay/sf/14zNnk9LpqKzBIc+w==", + "version": "5.33.5", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.5.tgz", + "integrity": "sha512-0v8l1CwFOAjfkv6ynpMrv3YGjH0M7PWCpZwusr8J1TEoQFPK7WXO6gbeAiandaWoh7vbMdnFtDqVotJVnLJtIg==", "dev": true, "license": "MIT", "os": [ @@ -3681,9 +3695,9 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -3876,9 +3890,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -3949,6 +3963,28 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yauzl": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", diff --git a/cypress-accessibility-checker/package.json b/cypress-accessibility-checker/package.json index 5ad5f2570..dc75d69c8 100644 --- a/cypress-accessibility-checker/package.json +++ b/cypress-accessibility-checker/package.json @@ -32,13 +32,13 @@ "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { "cypress": "^13.2.0 || ^15", - "exceljs": "^4.4.0" - }, - "peerDependenciesMeta": { - "exceljs": { - "optional": true - } - }, + "write-excel-file": "^4.1.1" + }, + "peerDependenciesMeta": { + "write-excel-file": { + "optional": true + } + }, "devDependencies": { "cypress": "^15.9.0", "eslint": "^8.4.1", diff --git a/karma-accessibility-checker/package.json b/karma-accessibility-checker/package.json index 90479e9c4..d79f400ae 100644 --- a/karma-accessibility-checker/package.json +++ b/karma-accessibility-checker/package.json @@ -44,10 +44,10 @@ "author": "Tom Brunet ", "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } }, diff --git a/report-react/package-lock.json b/report-react/package-lock.json index 365288517..c26e6c608 100644 --- a/report-react/package-lock.json +++ b/report-react/package-lock.json @@ -2113,9 +2113,9 @@ "license": "MIT" }, "node_modules/@carbon/colors": { - "version": "11.55.0", - "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.55.0.tgz", - "integrity": "sha512-02XkYCoo1GASrux+UofsPW+cgX58wf4LM5kpsitewvPuiA3/XI06Zzyss4yw/ammAHr3OruKzPmc/sNQZXlHCQ==", + "version": "11.57.0", + "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.57.0.tgz", + "integrity": "sha512-ji8xOBiCzCmeR/Pg/rDbnViVYDnjSVWRclylQKqeAQNUIsfIWDB69xq/o33lba3vVccVDNrGcGkrVg5My0Ct7g==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -2133,20 +2133,20 @@ } }, "node_modules/@carbon/grid": { - "version": "11.59.0", - "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.59.0.tgz", - "integrity": "sha512-sa+56qm1J/CZ2aGMeHRF9ui2YmmXBKdEvLtUV9W6t+ILub0e0/nS12HAEhbiuw8B0IqWjUpIQR6Lzaii6TcYSw==", + "version": "11.61.0", + "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.61.0.tgz", + "integrity": "sha512-kY6Zwi15kpdbT/RM8M7QciK5BVZhb0cEepvoP2uT0a04yTio4QMc8BZxIvXXMi8vf48AowUNkxbhYk8KlAf7EQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/layout": "^11.56.0", + "@carbon/layout": "^11.58.0", "@ibm/telemetry-js": "^1.5.0" } }, "node_modules/@carbon/icon-helpers": { - "version": "10.79.0", - "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.79.0.tgz", - "integrity": "sha512-sg5bL9Y/Vns4W7iNRaIMoNc/FtuzJE8G5VvCbC8xcrrNoZmfhhiPFHyU8CFhrf19HJdAxOvXShIBxmm3glLAYw==", + "version": "10.81.0", + "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.81.0.tgz", + "integrity": "sha512-3ga+ZpXzo+aL5rGSZu5xEdXGyEzSUGBe0IqvlcFxeav2gcrrE5w0G8ZAvUPsPWJXybjrXKW0CQaGAtsgNkmLLA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -2154,13 +2154,13 @@ } }, "node_modules/@carbon/icons-react": { - "version": "11.85.0", - "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.85.0.tgz", - "integrity": "sha512-+fRNYyqR8aCZRSgMA8sJ+GVfCmS0pK8FaDl9rQDuy4ZqYldZ4Yj8K3YIxmcSLlvTxMmNtGAxoa80xlhXROYDQg==", + "version": "11.87.0", + "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.87.0.tgz", + "integrity": "sha512-s3hYxy2qlWHZPjd44BpKx1jJAjYDWOLxO0xyJEcFiEqbqR3L+Sg+CeWuNR2L18AfslyNHg5wwB2+zASrwDC/yg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/icon-helpers": "^10.79.0", + "@carbon/icon-helpers": "^10.81.0", "@ibm/telemetry-js": "^1.5.0", "prop-types": "^15.8.1" }, @@ -2169,9 +2169,9 @@ } }, "node_modules/@carbon/layout": { - "version": "11.56.0", - "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.56.0.tgz", - "integrity": "sha512-61XxRnFkJdfSmsr30smEexrVOfHFZIzBPlTtW65CkRx8edAakc2eapxrW1sKFIfYQJildWPi7CivAvjA3cnlUg==", + "version": "11.58.0", + "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.58.0.tgz", + "integrity": "sha512-rVqN9tbpDD0rmyrCldAK2xUSjtusEOCxZqazuWgYFrusGsIpkQJ3ROmdHPkMfIgrpIaSr/RBGDbXXea/Qw7yJQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -2179,9 +2179,9 @@ } }, "node_modules/@carbon/motion": { - "version": "11.49.0", - "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.49.0.tgz", - "integrity": "sha512-HMSBS/tf1MVvXVJayw4jdNPsT79hn/fr31sVzowobErp/AyQGYk/t/NE7kFfOsQnARL0I3ITVEZelShfk1N87Q==", + "version": "11.51.0", + "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.51.0.tgz", + "integrity": "sha512-Is/lRo5iCw6XjQ8y4kXl2BepMJqZBYHVrlEnwyd0PJei+qhmTgpFJFSjUwdj9vRGUwPcWbcxEmY1aWa1gK2Rgw==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -2222,21 +2222,21 @@ } }, "node_modules/@carbon/styles": { - "version": "1.112.0", - "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.112.0.tgz", - "integrity": "sha512-7gU+nlckjO3n4dmfc/UQ9io6k5CoSYKW92wOJplhrOBtyNEwv00ZWcL/wx8xgVBNSGtg0Asbag2feHbhoapqpw==", + "version": "1.114.0", + "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.114.0.tgz", + "integrity": "sha512-795Z4PO2Tu/nuwFY0HGu2HTZTrKagaCSYf5ILOn/7hcmM+88R8BrNFZC961kxXitZv3RXmY0wV/oqqJ4scOQYA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/colors": "^11.55.0", - "@carbon/feature-flags": "^1.6.0", - "@carbon/grid": "^11.59.0", - "@carbon/layout": "^11.56.0", - "@carbon/motion": "^11.49.0", - "@carbon/themes": "^11.78.0", - "@carbon/type": "^11.64.0", + "@carbon/colors": "^11.57.0", + "@carbon/feature-flags": "^1.8.0", + "@carbon/grid": "^11.61.0", + "@carbon/layout": "^11.58.0", + "@carbon/motion": "^11.51.0", + "@carbon/themes": "^11.80.0", + "@carbon/type": "^11.66.0", "@ibm/plex": "6.4.1", - "@ibm/plex-mono": "1.1.0", + "@ibm/plex-mono": "2.5.0", "@ibm/plex-sans": "1.1.0", "@ibm/plex-sans-arabic": "1.1.0", "@ibm/plex-sans-devanagari": "1.1.0", @@ -2256,9 +2256,9 @@ } }, "node_modules/@carbon/styles/node_modules/@carbon/feature-flags": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-1.6.0.tgz", - "integrity": "sha512-VC6Rweb84VyDqA1wUZzZ/nNnR4QQiDkr5+of6cpzLUbgjLtL5aml9pIvjYeHnYKRVm6FeNFjnHY9wYVaSOvN/g==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-1.8.0.tgz", + "integrity": "sha512-bgdo6JRkG4yBOG58n+qlbBp3qzYrTZ33EEthNQY/ACsZm9gNUlxA7xOwesbNjryzAp4r5s9mKF4ZA6cackLnbQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -2266,28 +2266,31 @@ } }, "node_modules/@carbon/themes": { - "version": "11.78.0", - "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.78.0.tgz", - "integrity": "sha512-v0w90JjmWCq13chVvhQmjgTGRMp47OzKG7lsLJzFcWfK7kI0FvLIMWbS/tpKOP9Z6tWOjZhsSZm8UaaCd3cXQg==", + "version": "11.80.0", + "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.80.0.tgz", + "integrity": "sha512-SqtfqwReq1SRrBoC121Bllrh0DvW2j/LWFo/zVn+lblh+AJlLZsmeBC9oyxphpp8GpHfLhjmeg1J2hfs0AVX4A==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/colors": "^11.55.0", - "@carbon/layout": "^11.56.0", - "@carbon/type": "^11.64.0", + "@carbon/colors": "^11.57.0", + "@carbon/layout": "^11.58.0", + "@carbon/type": "^11.66.0", "@ibm/telemetry-js": "^1.5.0", "color": "^4.0.0" + }, + "engines": { + "node": ">=22" } }, "node_modules/@carbon/type": { - "version": "11.64.0", - "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.64.0.tgz", - "integrity": "sha512-ejnpUIbmyEbGkKWX3mzojKa3lOc3Jhoqhy7b4f2zi/nAV0uGu8KMXw978Cq/op3/WwOGYzwRf2viqTw6NNLWPQ==", + "version": "11.66.0", + "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.66.0.tgz", + "integrity": "sha512-8y9WtdXqqKAGnOyZvkRP7jqqQe+WcdRQDfsgOcpusszIoSBSVs2dv4gEwHjMYmzansLhsCUBNocSfWNFhkVDOg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@carbon/grid": "^11.59.0", - "@carbon/layout": "^11.56.0", + "@carbon/grid": "^11.61.0", + "@carbon/layout": "^11.58.0", "@ibm/telemetry-js": "^1.5.0" } }, @@ -2634,9 +2637,9 @@ "license": "Python-2.0" }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -2786,9 +2789,9 @@ } }, "node_modules/@ibm/plex-mono": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ibm/plex-mono/-/plex-mono-1.1.0.tgz", - "integrity": "sha512-hpsdRxR3BRJkC6wGM4MZcUFD6C8M+mmK76RtAy/hlsfPro9FzpXVdIWC+G3jeQOXof109dxlUvmeKxpeKUG68A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ibm/plex-mono/-/plex-mono-2.5.0.tgz", + "integrity": "sha512-STBJIPxPomOYPmBMO7z5TKPJUotAF9u3gAUumTqVgwgrAO+K4FRNh0MlhsoJjKhJKsMbBJR10/bk4inkj/wc1w==", "hasInstallScript": true, "license": "OFL-1.1", "dependencies": { @@ -3233,9 +3236,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -3596,9 +3599,9 @@ } }, "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "optional": true, "engines": { @@ -4665,9 +4668,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "license": "ISC" }, "node_modules/@webassemblyjs/ast": { @@ -5509,9 +5512,9 @@ } }, "node_modules/axe-core": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz", - "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.13.0.tgz", + "integrity": "sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==", "license": "MPL-2.0", "engines": { "node": ">=4" @@ -5802,9 +5805,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz", - "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz", + "integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -5838,9 +5841,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", - "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -6019,9 +6022,9 @@ "license": "BSD-2-Clause" }, "node_modules/browserslist": { - "version": "4.28.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", - "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", "funding": [ { "type": "opencollective", @@ -6038,11 +6041,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.44", - "caniuse-lite": "^1.0.30001806", - "electron-to-chromium": "^1.5.393", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" @@ -6212,9 +6215,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "funding": [ { "type": "opencollective", @@ -6516,9 +6519,9 @@ } }, "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.10.0.tgz", + "integrity": "sha512-AidJptpBJmjTclAp9BkLwJi0T93fo5epJnbaZslpg6QVzpHjAiveF55mE9AcUJiGMqRHgMDY8soMsQtuNYMHfw==", "license": "MIT" }, "node_modules/colorette": { @@ -6718,23 +6721,29 @@ } }, "node_modules/core-js": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", - "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.50.0.tgz", + "integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==", "hasInstallScript": true, "license": "MIT", + "engines": { + "node": "*" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, "node_modules/core-js-compat": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", - "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", + "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", "license": "MIT", "dependencies": { - "browserslist": "^4.28.1" + "browserslist": "^4.28.7" + }, + "engines": { + "node": ">=6.4.0" }, "funding": { "type": "opencollective", @@ -6742,11 +6751,14 @@ } }, "node_modules/core-js-pure": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.49.0.tgz", - "integrity": "sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==", + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.50.0.tgz", + "integrity": "sha512-6GP3Pxz4IKyWjAfa747vIu/jilB5z29JWROLqH/b+pXVcpgh6tM06ZIBwSuglgVqzDYURhOK6oEzTrG0bCHitA==", "hasInstallScript": true, "license": "MIT", + "engines": { + "node": "*" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -7719,9 +7731,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.400", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.400.tgz", - "integrity": "sha512-96EWDNjM59SYflgeV5Ylsf4EMiq1a25YjCnJH7cxn/AF2H3pILRweaUnoLax0yKHWdpOzY6JKEu45e8irqZIHA==", + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", "license": "ISC" }, "node_modules/emittery": { @@ -7946,9 +7958,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "license": "MIT" }, "node_modules/es-object-atoms": { @@ -8011,14 +8023,15 @@ } }, "node_modules/es-toolkit": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", - "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", "license": "MIT", "workspaces": [ "docs", "benchmarks", - "tests/types" + "tests/types", + "tests/browser-compat" ] }, "node_modules/escalade": { @@ -8586,9 +8599,9 @@ } }, "node_modules/eslint/node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -8954,9 +8967,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.6.tgz", + "integrity": "sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==", "funding": [ { "type": "github", @@ -8980,9 +8993,9 @@ } }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", + "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -10204,9 +10217,9 @@ } }, "node_modules/html-minifier-terser/node_modules/terser": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.1.tgz", - "integrity": "sha512-7A2xlQ5EnGT8KPA92dUh6RbRYTVw8hEaEN9L1K68l4UOXFuV511NnAqObGoRqGOQofQcMypisu1s3xawCEHrvA==", + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -10987,9 +11000,9 @@ } }, "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.1.0.tgz", + "integrity": "sha512-bUi/yjmtKYcRVUtWRGr0UA6xEFh2I6zWUwMrUXB3s7bmYCaZ8a+0ZsTRkrawh/mzlSD1Y0Ph8bp/U+TvBpWDNw==", "dev": true, "license": "MIT", "engines": { @@ -12237,9 +12250,9 @@ } }, "node_modules/jest-watch-typeahead/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "license": "MIT", "engines": { "node": ">=12" @@ -12311,9 +12324,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", - "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -12927,15 +12940,15 @@ } }, "node_modules/minimizer-webpack-plugin": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.6.1.tgz", - "integrity": "sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.8.0.tgz", + "integrity": "sha512-2cT9+goJfBhtMz+gJqejSf09ClgmYhPhccRb/fb0ztVbixt0BkO8mRuI26FoPPuUNkRk6iEDryWAIouc5W8eJA==", "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", + "@jridgewell/trace-mapping": "^0.3.31", "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "terser": "^5.31.1" + "schema-utils": "^4.3.3", + "terser": "^5.51.0" }, "engines": { "node": ">= 10.13.0" @@ -12993,9 +13006,9 @@ "license": "MIT" }, "node_modules/minimizer-webpack-plugin/node_modules/terser": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.1.tgz", - "integrity": "sha512-7A2xlQ5EnGT8KPA92dUh6RbRYTVw8hEaEN9L1K68l4UOXFuV511NnAqObGoRqGOQofQcMypisu1s3xawCEHrvA==", + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -13063,9 +13076,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", @@ -13167,9 +13180,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.52", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz", - "integrity": "sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "license": "MIT", "engines": { "node": ">=18" @@ -13234,9 +13247,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.24", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.24.tgz", - "integrity": "sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==", + "version": "2.2.25", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.25.tgz", + "integrity": "sha512-kktSgNDIbyEIs/LrE6dtEMnfzxSDpXViFl6c4gFjz/CgtnL4GDCR3wyZXzjvAXsNB8dXU4dAfvIOgLMH2/vwLg==", "license": "MIT" }, "node_modules/object-assign": { @@ -13750,15 +13763,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/pirates": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", @@ -13864,9 +13868,9 @@ } }, "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "funding": [ { "type": "opencollective", @@ -13883,7 +13887,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -14529,9 +14533,9 @@ } }, "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", - "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.5.tgz", + "integrity": "sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -14557,9 +14561,9 @@ } }, "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", - "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.5.tgz", + "integrity": "sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -15099,9 +15103,9 @@ } }, "node_modules/postcss-svgo/node_modules/svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.3.tgz", - "integrity": "sha512-5EZD0pafXX6PphdwOGCiVLDSaV1xyuQao2blHajHLsPxr07q4mmEjdtXEWgG07ae2mIz8Ex2CDXNCTiXhy3Khw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.4.tgz", + "integrity": "sha512-2GJ4h3rl13qYTdwllaK6QlL8tG+UrM8626V2Ylcd/yBUv2Y/EwLsYisVV6UDCRmlk+C74G8nMpxJCk0RWPdDCw==", "license": "MIT", "dependencies": { "commander": "^7.2.0", @@ -15650,13 +15654,10 @@ } }, "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.2.tgz", + "integrity": "sha512-/peqiBB/n07gQGLsWaHho3WfvUyRscw0gYTsEFMhrIe/nWLkYaf5SbKYjGYqtRV3aPwykJgF2VEMo1ac4bnsGA==", + "license": "MIT" }, "node_modules/readable-stream": { "version": "3.6.2", @@ -16325,9 +16326,9 @@ } }, "node_modules/rollup-plugin-terser/node_modules/terser": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.1.tgz", - "integrity": "sha512-7A2xlQ5EnGT8KPA92dUh6RbRYTVw8hEaEN9L1K68l4UOXFuV511NnAqObGoRqGOQofQcMypisu1s3xawCEHrvA==", + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -16450,9 +16451,9 @@ "license": "CC0-1.0" }, "node_modules/sass": { - "version": "1.102.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.102.0.tgz", - "integrity": "sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==", + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.103.1.tgz", + "integrity": "sha512-9icZURbP51S6S0QGoyaeqk9uB06GNWxsFYWfH5RgpFgqK5FA8tJcM3AdVxrZEVJ7dz+L87nG95gBKf4VuaMHGw==", "license": "MIT", "dependencies": { "chokidar": "^5.0.0", @@ -16523,9 +16524,9 @@ } }, "node_modules/sass/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -17210,9 +17211,9 @@ "license": "MIT" }, "node_modules/streamx": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz", - "integrity": "sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==", + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz", + "integrity": "sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==", "dev": true, "license": "MIT", "dependencies": { @@ -17616,10 +17617,13 @@ } }, "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.1.0.tgz", + "integrity": "sha512-bwLf38YmY+TDYHJw1Ex0Co8c4yeXuJAo8YnXGZrscxrvYoVVIvLeniEkV1Ks/54VteMnL4FtyN1+P+TZJdUPmQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } }, "node_modules/svgo": { "version": "1.2.2", @@ -18062,9 +18066,9 @@ "license": "MIT" }, "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.1.tgz", - "integrity": "sha512-7A2xlQ5EnGT8KPA92dUh6RbRYTVw8hEaEN9L1K68l4UOXFuV511NnAqObGoRqGOQofQcMypisu1s3xawCEHrvA==", + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -18272,9 +18276,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "engines": { "node": ">=12" @@ -18742,9 +18746,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "funding": [ { "type": "opencollective", @@ -18840,9 +18844,9 @@ } }, "node_modules/uuid": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", - "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", + "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -19052,9 +19056,9 @@ } }, "node_modules/webpack": { - "version": "5.109.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz", - "integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==", + "version": "5.110.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.1.tgz", + "integrity": "sha512-gInQB+jxXxgnZyvPwuzT5NGQmECDqeu85oxcrjinrYHqPoBex0hCAN2SFTJVyPVrK0Pq9E44VFP+e89fAc10/w==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", @@ -19067,11 +19071,10 @@ "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.24.4", "es-module-lexer": "^2.1.0", - "eslint-scope": "5.1.1", "events": "^3.2.0", "graceful-fs": "^4.2.11", "mime-db": "^1.54.0", - "minimizer-webpack-plugin": "^5.6.1", + "minimizer-webpack-plugin": "^5.7.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", @@ -19177,9 +19180,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz", - "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -19244,28 +19247,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/webpack/node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", diff --git a/rule-server/package-lock.json b/rule-server/package-lock.json index 1edb7be07..db3a9429e 100644 --- a/rule-server/package-lock.json +++ b/rule-server/package-lock.json @@ -79,13 +79,13 @@ } }, "node_modules/@ibm-cloud/cloudant": { - "version": "0.12.23", - "resolved": "https://registry.npmjs.org/@ibm-cloud/cloudant/-/cloudant-0.12.23.tgz", - "integrity": "sha512-WYQp4DWZ9r1YXBVmkq7kCvh3jEKVyfGAKe/JLa+lOc8zb12ZxaazyDehfrJhW0D8Wa9Pta5mvZIKVw4HMzKtzg==", + "version": "0.12.24", + "resolved": "https://registry.npmjs.org/@ibm-cloud/cloudant/-/cloudant-0.12.24.tgz", + "integrity": "sha512-e6AyExQPGZP1c3WsDQ1NmjkR2HPoTXnkCRFEnFsqdCO8KSXbL1l7oQHGShcMiURW2RZkj3CKwcm7bfG0JXCJ2A==", "license": "Apache-2.0", "dependencies": { - "@types/node": "22.20.0", - "ibm-cloud-sdk-core": "5.5.0" + "@types/node": "22.20.1", + "ibm-cloud-sdk-core": "5.6.0" }, "engines": { "node": "^22 || ^24" @@ -97,9 +97,9 @@ } }, "node_modules/@ibm-cloud/cloudant/node_modules/@types/node": { - "version": "22.20.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz", - "integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==", + "version": "22.20.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -116,9 +116,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -180,9 +180,9 @@ "license": "MIT" }, "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", "dev": true, "license": "MIT" }, @@ -910,9 +910,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz", - "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz", + "integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -2451,9 +2451,9 @@ } }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", + "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", "dev": true, "license": "ISC", "dependencies": { @@ -4175,9 +4175,9 @@ "license": "MIT" }, "node_modules/ibm-cloud-sdk-core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-5.5.0.tgz", - "integrity": "sha512-ot6sGHAvSnd/ZSU4ZFn+m7i+xcFo3pmA3qm2JmEndDkMsuNR8HLdUeJ5iBbmkUfCGbf2ccTu/GvoJgFetyO6XA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-5.6.0.tgz", + "integrity": "sha512-7balLY8WKk+bOhe5Vgg4zG2X6Z0zhpG/3VtYPC69evj+lVJSId8xYP7ISRzRfoeXAlJfzLNMbi2Na/0IdDiIkQ==", "license": "Apache-2.0", "dependencies": { "@types/debug": "4.1.12", @@ -4735,9 +4735,9 @@ } }, "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.1.0.tgz", + "integrity": "sha512-bUi/yjmtKYcRVUtWRGr0UA6xEFh2I6zWUwMrUXB3s7bmYCaZ8a+0ZsTRkrawh/mzlSD1Y0Ph8bp/U+TvBpWDNw==", "dev": true, "license": "MIT", "engines": { @@ -5526,9 +5526,9 @@ "license": "MIT" }, "node_modules/multer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.2.0.tgz", - "integrity": "sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.3.0.tgz", + "integrity": "sha512-cjNbm3sttszgZeGfJR124D+jFEfkXCVAsoPBmFn9X7UxmDSFHWqE2CoEj0vrmSpuAFnqWR1Szcm9QTsiHr60Xw==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", @@ -7182,9 +7182,9 @@ } }, "node_modules/streamx": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz", - "integrity": "sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==", + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz", + "integrity": "sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/vitest-accessibility-checker/boilerplates/vitest/package-lock.json b/vitest-accessibility-checker/boilerplates/vitest/package-lock.json index 7d4b62549..dc5c0555f 100644 --- a/vitest-accessibility-checker/boilerplates/vitest/package-lock.json +++ b/vitest-accessibility-checker/boilerplates/vitest/package-lock.json @@ -38,16 +38,16 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, "node_modules/@oxc-project/types": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", - "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "version": "0.147.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz", + "integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==", "dev": true, "license": "MIT", "funding": { @@ -61,10 +61,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.6.tgz", + "integrity": "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.2.tgz", - "integrity": "sha512-l7x215OGvo1s52JWmR8U/DAVzEDWBCIbTm28aeJV/WDTSHgcKXaZTuBT0hJMs5NggilfJTW3clZVvd24yfKJxA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.6.tgz", + "integrity": "sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==", "cpu": [ "arm64" ], @@ -79,9 +96,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.2.tgz", - "integrity": "sha512-9u9Xv6c1AJZT0FfwH5vrMG5Jjcwhc1MlyrPu0XfTqkzsmqfks2M6W/o5XwAJgVVN/jHpqqngC1WevHKKTIUtIA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.6.tgz", + "integrity": "sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==", "cpu": [ "arm64" ], @@ -96,9 +113,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.2.tgz", - "integrity": "sha512-9W1mbGZAfW3oqd85bhBkmpyHCCzL1TeG/zFFP3vg7b0rlly8cxOcre5nXwz+LHazCwac2MNWgPdPCHndABjpWQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.6.tgz", + "integrity": "sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==", "cpu": [ "x64" ], @@ -113,9 +130,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.2.tgz", - "integrity": "sha512-0p1lhiCSCyaerFwtrdZQUx7NqGk6LQnaRKWX7tFQqwQgvX0rjM15cIkm3pax1UpEakK14C4mOxx/jSqCBdBRqQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.6.tgz", + "integrity": "sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==", "cpu": [ "x64" ], @@ -130,9 +147,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.2.tgz", - "integrity": "sha512-e+cOJXrJ2L3zx6YzqPg+f6Wbk3V1cKB8bOhbaYdVYN3DdquzNdRAmrbETz1qnt5yp/c7JNlNjmITiA2cVneQ7w==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.6.tgz", + "integrity": "sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==", "cpu": [ "arm" ], @@ -147,9 +164,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.2.tgz", - "integrity": "sha512-JsSMsj6sNat/MuhG5fnBD7QgbtpHKVe30x5/bAVirDHdhoQRXJkF6xc0Jqk8O4fiCUQAzMOoH9wZi3m60c8wtg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.6.tgz", + "integrity": "sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==", "cpu": [ "arm64" ], @@ -164,9 +181,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.2.tgz", - "integrity": "sha512-B5G/zJdHaoJn9vD50eGHWkiWfmq8Uhi3IiLPJTzmZTrAalk1bztUikSXo0qga18ibE0IXboyeMUnhPjhAJ45wQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.6.tgz", + "integrity": "sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==", "cpu": [ "arm64" ], @@ -181,9 +198,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.2.tgz", - "integrity": "sha512-6mC/awzKka8W6EoekjegpfGkjz8jXWDX63pqu/HYVpyKtZfu65Jsh4QAH3Kej3CAv/c1oGX7psTmFEbr0mDxLA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.6.tgz", + "integrity": "sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==", "cpu": [ "ppc64" ], @@ -198,9 +215,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.2.tgz", - "integrity": "sha512-412MX9fJLdA1IK28EZnc8jYv2HRTleOZgfLQumJ5zy7OeJLZlg/CETwFaXjNmGVxG51cFHpKLqb5LKvBC+HsHA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.6.tgz", + "integrity": "sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==", "cpu": [ "s390x" ], @@ -215,9 +232,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.2.tgz", - "integrity": "sha512-Q/+HI/ToJafZ1iCqGgVQXUEkIjufHCTF0gBQ2a5o3cg7GJ2h0qyq3nvvSmU+bGda2/7ygXpTY4TM6gO9OhQ0ZA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.6.tgz", + "integrity": "sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==", "cpu": [ "x64" ], @@ -232,9 +249,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.2.tgz", - "integrity": "sha512-ZKp/w41n6wCvxzxQHtQSbuphfX3Y4cCvbjkKHusrLx4lh+JWLTU7StSltO/DKARISzbj368d+qUaCjI8K2wzXw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.6.tgz", + "integrity": "sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==", "cpu": [ "x64" ], @@ -249,9 +266,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.2.tgz", - "integrity": "sha512-pxE6xD4KS3eAROkKK5yrhB9/3+vhlhVGMvlQLbdpzrBGDbKrnzx3RLwPaHvasLo6jgaiBLn7e04Df9C4tYhjmA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.6.tgz", + "integrity": "sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==", "cpu": [ "arm64" ], @@ -266,9 +283,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.2.tgz", - "integrity": "sha512-4MqEue5re+xIZzAWsB8sj0P1kqZySWqIuN4t6QaIO/YA6SFwySOLruvWQFzfmqk8LBK2P30KCSJwf6mJCZZ5/A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.6.tgz", + "integrity": "sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==", "cpu": [ "arm64" ], @@ -283,9 +300,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.2.tgz", - "integrity": "sha512-NweNxxD0Nf9t8v7kodun45Ijp3EIwYY+uydPP6qBEYvfBqhIjN6dZMzlQja3tqX/aLs3F3Uz+AxDpKgRhpOZQg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.6.tgz", + "integrity": "sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==", "cpu": [ "x64" ], @@ -339,9 +356,9 @@ "license": "MIT" }, "node_modules/@vitejs/plugin-react": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.5.tgz", - "integrity": "sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.1.tgz", + "integrity": "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==", "dev": true, "license": "MIT", "dependencies": { @@ -353,6 +370,7 @@ "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", + "oxc-transform-react": "^0.145.0", "vite": "^8.0.0" }, "peerDependenciesMeta": { @@ -361,19 +379,22 @@ }, "babel-plugin-react-compiler": { "optional": true + }, + "oxc-transform-react": { + "optional": true } } }, "node_modules/@vitest/browser": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz", - "integrity": "sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.11.tgz", + "integrity": "sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w==", "dev": true, "license": "MIT", "dependencies": { "@blazediff/core": "1.9.1", - "@vitest/mocker": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/mocker": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pngjs": "^7.0.0", "sirv": "^3.0.2", @@ -384,18 +405,18 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "4.1.10" + "vitest": "4.1.11" } }, "node_modules/@vitest/browser-playwright": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.10.tgz", - "integrity": "sha512-nMoXGEiRpT7m3W7NsbvrM2aKNwiNHZf+zEpUCvMteGjZFvfT96Q9fh7QyB98dvDWXiKvrLxA7bJ1mCOOv+JQPw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.11.tgz", + "integrity": "sha512-riLBxPqwnJ0lWs2DN2WeUfYeKLoAjbP2Xx8cLQdSddzMi20sksIa6K2mPz79DyMZKKVKH2ksOC2yJvtNcZg8cg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/browser": "4.1.10", - "@vitest/mocker": "4.1.10", + "@vitest/browser": "4.1.11", + "@vitest/mocker": "4.1.11", "tinyrainbow": "^3.1.0" }, "funding": { @@ -403,7 +424,7 @@ }, "peerDependencies": { "playwright": "*", - "vitest": "4.1.10" + "vitest": "4.1.11" }, "peerDependenciesMeta": { "playwright": { @@ -412,16 +433,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -430,13 +451,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -457,9 +478,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -470,13 +491,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.10", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -484,14 +505,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -500,9 +521,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -510,13 +531,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -562,9 +583,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "dev": true, "license": "MIT", "dependencies": { @@ -692,9 +713,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "dev": true, "license": "MIT" }, @@ -938,9 +959,9 @@ } }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -1289,9 +1310,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -1336,9 +1357,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -1393,9 +1414,9 @@ } }, "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "dev": true, "funding": [ { @@ -1413,7 +1434,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -1453,13 +1474,13 @@ } }, "node_modules/rolldown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.2.tgz", - "integrity": "sha512-opwpo1tQBAcpSUJDt94B7hhLNGOKjCdE//XXjeLrnx9b83bjnw45tXdg1b09yEw/VLFBJGZpwRULMmOZo7ol+A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz", + "integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.142.0", + "@oxc-project/types": "=0.147.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -1469,20 +1490,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.2", - "@rolldown/binding-darwin-arm64": "1.2.2", - "@rolldown/binding-darwin-x64": "1.2.2", - "@rolldown/binding-freebsd-x64": "1.2.2", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.2", - "@rolldown/binding-linux-arm64-gnu": "1.2.2", - "@rolldown/binding-linux-arm64-musl": "1.2.2", - "@rolldown/binding-linux-ppc64-gnu": "1.2.2", - "@rolldown/binding-linux-s390x-gnu": "1.2.2", - "@rolldown/binding-linux-x64-gnu": "1.2.2", - "@rolldown/binding-linux-x64-musl": "1.2.2", - "@rolldown/binding-openharmony-arm64": "1.2.2", - "@rolldown/binding-win32-arm64-msvc": "1.2.2", - "@rolldown/binding-win32-x64-msvc": "1.2.2" + "@rolldown/binding-android-arm-eabi": "1.2.6", + "@rolldown/binding-android-arm64": "1.2.6", + "@rolldown/binding-darwin-arm64": "1.2.6", + "@rolldown/binding-darwin-x64": "1.2.6", + "@rolldown/binding-freebsd-x64": "1.2.6", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.6", + "@rolldown/binding-linux-arm64-gnu": "1.2.6", + "@rolldown/binding-linux-arm64-musl": "1.2.6", + "@rolldown/binding-linux-ppc64-gnu": "1.2.6", + "@rolldown/binding-linux-s390x-gnu": "1.2.6", + "@rolldown/binding-linux-x64-gnu": "1.2.6", + "@rolldown/binding-linux-x64-musl": "1.2.6", + "@rolldown/binding-openharmony-arm64": "1.2.6", + "@rolldown/binding-win32-arm64-msvc": "1.2.6", + "@rolldown/binding-win32-x64-msvc": "1.2.6" } }, "node_modules/scheduler": { @@ -1592,16 +1614,16 @@ } }, "node_modules/vite": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", - "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", - "postcss": "^8.5.23", - "rolldown": "~1.2.0", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", "tinyglobby": "^0.2.17" }, "bin": { @@ -1618,7 +1640,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -1685,19 +1707,19 @@ } }, "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -1725,12 +1747,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -1775,9 +1797,9 @@ } }, "node_modules/vitest-accessibility-checker": { - "version": "4.0.29", - "resolved": "https://registry.npmjs.org/vitest-accessibility-checker/-/vitest-accessibility-checker-4.0.29.tgz", - "integrity": "sha512-XAnin5jUo+m+R9Jzx+UuUed5M0PCIGxT0AeCk4bGpZ3zCWvB0Gr4MjRek7iy0OUV79cHl1qlfGrDxMGu0IeTTQ==", + "version": "4.0.31", + "resolved": "https://registry.npmjs.org/vitest-accessibility-checker/-/vitest-accessibility-checker-4.0.31.tgz", + "integrity": "sha512-RF1OzrvfZpDKZtqXLRezd+rGLpPBPK8fmeC7w7fR9Paw06Kiqan3DT106kihrsVSgDPFfijruoUU78kOcH8j3w==", "dev": true, "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", @@ -1840,9 +1862,9 @@ } }, "node_modules/ws": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz", - "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { diff --git a/vitest-accessibility-checker/package-lock.json b/vitest-accessibility-checker/package-lock.json index 0ccba33e5..a7316fa7d 100644 --- a/vitest-accessibility-checker/package-lock.json +++ b/vitest-accessibility-checker/package-lock.json @@ -28,11 +28,11 @@ "vitest": "^4.1.6" }, "peerDependencies": { - "exceljs": "^4.4.0", - "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0" + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } } @@ -155,9 +155,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -200,9 +200,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", - "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "version": "0.147.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz", + "integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==", "dev": true, "license": "MIT", "funding": { @@ -216,10 +216,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.6.tgz", + "integrity": "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.2.tgz", - "integrity": "sha512-l7x215OGvo1s52JWmR8U/DAVzEDWBCIbTm28aeJV/WDTSHgcKXaZTuBT0hJMs5NggilfJTW3clZVvd24yfKJxA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.6.tgz", + "integrity": "sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==", "cpu": [ "arm64" ], @@ -234,9 +251,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.2.tgz", - "integrity": "sha512-9u9Xv6c1AJZT0FfwH5vrMG5Jjcwhc1MlyrPu0XfTqkzsmqfks2M6W/o5XwAJgVVN/jHpqqngC1WevHKKTIUtIA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.6.tgz", + "integrity": "sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==", "cpu": [ "arm64" ], @@ -251,9 +268,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.2.tgz", - "integrity": "sha512-9W1mbGZAfW3oqd85bhBkmpyHCCzL1TeG/zFFP3vg7b0rlly8cxOcre5nXwz+LHazCwac2MNWgPdPCHndABjpWQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.6.tgz", + "integrity": "sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==", "cpu": [ "x64" ], @@ -268,9 +285,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.2.tgz", - "integrity": "sha512-0p1lhiCSCyaerFwtrdZQUx7NqGk6LQnaRKWX7tFQqwQgvX0rjM15cIkm3pax1UpEakK14C4mOxx/jSqCBdBRqQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.6.tgz", + "integrity": "sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==", "cpu": [ "x64" ], @@ -285,9 +302,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.2.tgz", - "integrity": "sha512-e+cOJXrJ2L3zx6YzqPg+f6Wbk3V1cKB8bOhbaYdVYN3DdquzNdRAmrbETz1qnt5yp/c7JNlNjmITiA2cVneQ7w==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.6.tgz", + "integrity": "sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==", "cpu": [ "arm" ], @@ -302,16 +319,13 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.2.tgz", - "integrity": "sha512-JsSMsj6sNat/MuhG5fnBD7QgbtpHKVe30x5/bAVirDHdhoQRXJkF6xc0Jqk8O4fiCUQAzMOoH9wZi3m60c8wtg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.6.tgz", + "integrity": "sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -322,16 +336,13 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.2.tgz", - "integrity": "sha512-B5G/zJdHaoJn9vD50eGHWkiWfmq8Uhi3IiLPJTzmZTrAalk1bztUikSXo0qga18ibE0IXboyeMUnhPjhAJ45wQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.6.tgz", + "integrity": "sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -342,16 +353,13 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.2.tgz", - "integrity": "sha512-6mC/awzKka8W6EoekjegpfGkjz8jXWDX63pqu/HYVpyKtZfu65Jsh4QAH3Kej3CAv/c1oGX7psTmFEbr0mDxLA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.6.tgz", + "integrity": "sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==", "cpu": [ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -362,16 +370,13 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.2.tgz", - "integrity": "sha512-412MX9fJLdA1IK28EZnc8jYv2HRTleOZgfLQumJ5zy7OeJLZlg/CETwFaXjNmGVxG51cFHpKLqb5LKvBC+HsHA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.6.tgz", + "integrity": "sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==", "cpu": [ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -382,16 +387,13 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.2.tgz", - "integrity": "sha512-Q/+HI/ToJafZ1iCqGgVQXUEkIjufHCTF0gBQ2a5o3cg7GJ2h0qyq3nvvSmU+bGda2/7ygXpTY4TM6gO9OhQ0ZA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.6.tgz", + "integrity": "sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -402,16 +404,13 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.2.tgz", - "integrity": "sha512-ZKp/w41n6wCvxzxQHtQSbuphfX3Y4cCvbjkKHusrLx4lh+JWLTU7StSltO/DKARISzbj368d+qUaCjI8K2wzXw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.6.tgz", + "integrity": "sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -422,9 +421,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.2.tgz", - "integrity": "sha512-pxE6xD4KS3eAROkKK5yrhB9/3+vhlhVGMvlQLbdpzrBGDbKrnzx3RLwPaHvasLo6jgaiBLn7e04Df9C4tYhjmA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.6.tgz", + "integrity": "sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==", "cpu": [ "arm64" ], @@ -439,9 +438,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.2.tgz", - "integrity": "sha512-4MqEue5re+xIZzAWsB8sj0P1kqZySWqIuN4t6QaIO/YA6SFwySOLruvWQFzfmqk8LBK2P30KCSJwf6mJCZZ5/A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.6.tgz", + "integrity": "sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==", "cpu": [ "arm64" ], @@ -456,9 +455,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.2.tgz", - "integrity": "sha512-NweNxxD0Nf9t8v7kodun45Ijp3EIwYY+uydPP6qBEYvfBqhIjN6dZMzlQja3tqX/aLs3F3Uz+AxDpKgRhpOZQg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.6.tgz", + "integrity": "sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==", "cpu": [ "x64" ], @@ -512,22 +511,22 @@ "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "dev": true, "license": "ISC" }, "node_modules/@vitest/browser": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz", - "integrity": "sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.11.tgz", + "integrity": "sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w==", "dev": true, "license": "MIT", "dependencies": { "@blazediff/core": "1.9.1", - "@vitest/mocker": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/mocker": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pngjs": "^7.0.0", "sirv": "^3.0.2", @@ -538,18 +537,18 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "4.1.10" + "vitest": "4.1.11" } }, "node_modules/@vitest/browser-playwright": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.10.tgz", - "integrity": "sha512-nMoXGEiRpT7m3W7NsbvrM2aKNwiNHZf+zEpUCvMteGjZFvfT96Q9fh7QyB98dvDWXiKvrLxA7bJ1mCOOv+JQPw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.11.tgz", + "integrity": "sha512-riLBxPqwnJ0lWs2DN2WeUfYeKLoAjbP2Xx8cLQdSddzMi20sksIa6K2mPz79DyMZKKVKH2ksOC2yJvtNcZg8cg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/browser": "4.1.10", - "@vitest/mocker": "4.1.10", + "@vitest/browser": "4.1.11", + "@vitest/mocker": "4.1.11", "tinyrainbow": "^3.1.0" }, "funding": { @@ -557,7 +556,7 @@ }, "peerDependencies": { "playwright": "*", - "vitest": "4.1.10" + "vitest": "4.1.11" }, "peerDependenciesMeta": { "playwright": { @@ -566,16 +565,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -584,13 +583,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -611,9 +610,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -624,13 +623,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.10", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -638,14 +637,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -654,9 +653,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -664,13 +663,13 @@ } }, "node_modules/@vitest/ui": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.10.tgz", - "integrity": "sha512-EOUqfXHTXtpSHsyLHH40ts3Ue+hRhSGwzwzMlK0dTEOLSDYyOXLyr5JDGmHQWhN2DYI30gw6dVx3cdgM9FZl+Q==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.11.tgz", + "integrity": "sha512-r/rwyKoev21mWdRGSEkZOqkQ2BYy68mwjihg9M90nNRbf4NGrgzZ4cj6JNCEwlOGJkbKeMgsjlykvwKUbRr7gw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.10", + "@vitest/utils": "4.1.11", "fflate": "^0.8.2", "flatted": "^3.4.2", "pathe": "^2.0.3", @@ -682,17 +681,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "4.1.10" + "vitest": "4.1.11" } }, "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -808,9 +807,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", @@ -1077,9 +1076,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "dev": true, "license": "MIT" }, @@ -1323,9 +1322,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", + "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", "dev": true, "license": "ISC", "dependencies": { @@ -1847,9 +1846,9 @@ "license": "ISC" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -2056,9 +2055,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2080,9 +2076,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2104,9 +2097,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2128,9 +2118,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2308,9 +2295,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -2495,9 +2482,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -2564,9 +2551,9 @@ } }, "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "dev": true, "funding": [ { @@ -2584,7 +2571,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2755,13 +2742,13 @@ } }, "node_modules/rolldown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.2.tgz", - "integrity": "sha512-opwpo1tQBAcpSUJDt94B7hhLNGOKjCdE//XXjeLrnx9b83bjnw45tXdg1b09yEw/VLFBJGZpwRULMmOZo7ol+A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz", + "integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.142.0", + "@oxc-project/types": "=0.147.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -2771,20 +2758,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.2", - "@rolldown/binding-darwin-arm64": "1.2.2", - "@rolldown/binding-darwin-x64": "1.2.2", - "@rolldown/binding-freebsd-x64": "1.2.2", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.2", - "@rolldown/binding-linux-arm64-gnu": "1.2.2", - "@rolldown/binding-linux-arm64-musl": "1.2.2", - "@rolldown/binding-linux-ppc64-gnu": "1.2.2", - "@rolldown/binding-linux-s390x-gnu": "1.2.2", - "@rolldown/binding-linux-x64-gnu": "1.2.2", - "@rolldown/binding-linux-x64-musl": "1.2.2", - "@rolldown/binding-openharmony-arm64": "1.2.2", - "@rolldown/binding-win32-arm64-msvc": "1.2.2", - "@rolldown/binding-win32-x64-msvc": "1.2.2" + "@rolldown/binding-android-arm-eabi": "1.2.6", + "@rolldown/binding-android-arm64": "1.2.6", + "@rolldown/binding-darwin-arm64": "1.2.6", + "@rolldown/binding-darwin-x64": "1.2.6", + "@rolldown/binding-freebsd-x64": "1.2.6", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.6", + "@rolldown/binding-linux-arm64-gnu": "1.2.6", + "@rolldown/binding-linux-arm64-musl": "1.2.6", + "@rolldown/binding-linux-ppc64-gnu": "1.2.6", + "@rolldown/binding-linux-s390x-gnu": "1.2.6", + "@rolldown/binding-linux-x64-gnu": "1.2.6", + "@rolldown/binding-linux-x64-musl": "1.2.6", + "@rolldown/binding-openharmony-arm64": "1.2.6", + "@rolldown/binding-win32-arm64-msvc": "1.2.6", + "@rolldown/binding-win32-x64-msvc": "1.2.6" } }, "node_modules/run-parallel": { @@ -3181,16 +3169,16 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", - "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", - "postcss": "^8.5.23", - "rolldown": "~1.2.0", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", "tinyglobby": "^0.2.17" }, "bin": { @@ -3207,7 +3195,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -3274,19 +3262,19 @@ } }, "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -3314,12 +3302,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -3428,9 +3416,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz", - "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { diff --git a/vitest-accessibility-checker/package.json b/vitest-accessibility-checker/package.json index d2a8c89c3..1aa34ddac 100644 --- a/vitest-accessibility-checker/package.json +++ b/vitest-accessibility-checker/package.json @@ -34,10 +34,10 @@ "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } }, diff --git a/vitest-accessibility-checker/src/package-lock.json b/vitest-accessibility-checker/src/package-lock.json index aae44f2d6..4288c9ef8 100644 --- a/vitest-accessibility-checker/src/package-lock.json +++ b/vitest-accessibility-checker/src/package-lock.json @@ -16,11 +16,11 @@ "microdiff": "^1.5.0" }, "peerDependencies": { - "exceljs": "^4.4.0", - "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0" + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } } @@ -35,26 +35,43 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT", "peer": true }, "node_modules/@oxc-project/types": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", - "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "version": "0.147.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz", + "integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==", "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.6.tgz", + "integrity": "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.2.tgz", - "integrity": "sha512-l7x215OGvo1s52JWmR8U/DAVzEDWBCIbTm28aeJV/WDTSHgcKXaZTuBT0hJMs5NggilfJTW3clZVvd24yfKJxA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.6.tgz", + "integrity": "sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==", "cpu": [ "arm64" ], @@ -69,9 +86,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.2.tgz", - "integrity": "sha512-9u9Xv6c1AJZT0FfwH5vrMG5Jjcwhc1MlyrPu0XfTqkzsmqfks2M6W/o5XwAJgVVN/jHpqqngC1WevHKKTIUtIA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.6.tgz", + "integrity": "sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==", "cpu": [ "arm64" ], @@ -86,9 +103,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.2.tgz", - "integrity": "sha512-9W1mbGZAfW3oqd85bhBkmpyHCCzL1TeG/zFFP3vg7b0rlly8cxOcre5nXwz+LHazCwac2MNWgPdPCHndABjpWQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.6.tgz", + "integrity": "sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==", "cpu": [ "x64" ], @@ -103,9 +120,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.2.tgz", - "integrity": "sha512-0p1lhiCSCyaerFwtrdZQUx7NqGk6LQnaRKWX7tFQqwQgvX0rjM15cIkm3pax1UpEakK14C4mOxx/jSqCBdBRqQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.6.tgz", + "integrity": "sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==", "cpu": [ "x64" ], @@ -120,9 +137,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.2.tgz", - "integrity": "sha512-e+cOJXrJ2L3zx6YzqPg+f6Wbk3V1cKB8bOhbaYdVYN3DdquzNdRAmrbETz1qnt5yp/c7JNlNjmITiA2cVneQ7w==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.6.tgz", + "integrity": "sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==", "cpu": [ "arm" ], @@ -137,9 +154,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.2.tgz", - "integrity": "sha512-JsSMsj6sNat/MuhG5fnBD7QgbtpHKVe30x5/bAVirDHdhoQRXJkF6xc0Jqk8O4fiCUQAzMOoH9wZi3m60c8wtg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.6.tgz", + "integrity": "sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==", "cpu": [ "arm64" ], @@ -154,9 +171,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.2.tgz", - "integrity": "sha512-B5G/zJdHaoJn9vD50eGHWkiWfmq8Uhi3IiLPJTzmZTrAalk1bztUikSXo0qga18ibE0IXboyeMUnhPjhAJ45wQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.6.tgz", + "integrity": "sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==", "cpu": [ "arm64" ], @@ -171,9 +188,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.2.tgz", - "integrity": "sha512-6mC/awzKka8W6EoekjegpfGkjz8jXWDX63pqu/HYVpyKtZfu65Jsh4QAH3Kej3CAv/c1oGX7psTmFEbr0mDxLA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.6.tgz", + "integrity": "sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==", "cpu": [ "ppc64" ], @@ -188,9 +205,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.2.tgz", - "integrity": "sha512-412MX9fJLdA1IK28EZnc8jYv2HRTleOZgfLQumJ5zy7OeJLZlg/CETwFaXjNmGVxG51cFHpKLqb5LKvBC+HsHA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.6.tgz", + "integrity": "sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==", "cpu": [ "s390x" ], @@ -205,9 +222,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.2.tgz", - "integrity": "sha512-Q/+HI/ToJafZ1iCqGgVQXUEkIjufHCTF0gBQ2a5o3cg7GJ2h0qyq3nvvSmU+bGda2/7ygXpTY4TM6gO9OhQ0ZA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.6.tgz", + "integrity": "sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==", "cpu": [ "x64" ], @@ -222,9 +239,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.2.tgz", - "integrity": "sha512-ZKp/w41n6wCvxzxQHtQSbuphfX3Y4cCvbjkKHusrLx4lh+JWLTU7StSltO/DKARISzbj368d+qUaCjI8K2wzXw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.6.tgz", + "integrity": "sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==", "cpu": [ "x64" ], @@ -239,9 +256,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.2.tgz", - "integrity": "sha512-pxE6xD4KS3eAROkKK5yrhB9/3+vhlhVGMvlQLbdpzrBGDbKrnzx3RLwPaHvasLo6jgaiBLn7e04Df9C4tYhjmA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.6.tgz", + "integrity": "sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==", "cpu": [ "arm64" ], @@ -256,9 +273,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.2.tgz", - "integrity": "sha512-4MqEue5re+xIZzAWsB8sj0P1kqZySWqIuN4t6QaIO/YA6SFwySOLruvWQFzfmqk8LBK2P30KCSJwf6mJCZZ5/A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.6.tgz", + "integrity": "sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==", "cpu": [ "arm64" ], @@ -273,9 +290,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.2.tgz", - "integrity": "sha512-NweNxxD0Nf9t8v7kodun45Ijp3EIwYY+uydPP6qBEYvfBqhIjN6dZMzlQja3tqX/aLs3F3Uz+AxDpKgRhpOZQg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.6.tgz", + "integrity": "sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==", "cpu": [ "x64" ], @@ -329,16 +346,16 @@ "peer": true }, "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "license": "MIT", "peer": true, "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -347,13 +364,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "license": "MIT", "peer": true, "dependencies": { - "@vitest/spy": "4.1.10", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -374,9 +391,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "license": "MIT", "peer": true, "dependencies": { @@ -387,13 +404,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "license": "MIT", "peer": true, "dependencies": { - "@vitest/utils": "4.1.10", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -401,14 +418,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "license": "MIT", "peer": true, "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -417,9 +434,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "license": "MIT", "peer": true, "funding": { @@ -427,13 +444,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "license": "MIT", "peer": true, "dependencies": { - "@vitest/pretty-format": "4.1.10", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -476,9 +493,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", @@ -598,9 +615,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "license": "MIT", "peer": true }, @@ -831,9 +848,9 @@ } }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -1166,9 +1183,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", @@ -1213,9 +1230,9 @@ "peer": true }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "peer": true, "engines": { @@ -1226,9 +1243,9 @@ } }, "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "funding": [ { "type": "opencollective", @@ -1246,7 +1263,7 @@ "license": "MIT", "peer": true, "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -1264,13 +1281,13 @@ } }, "node_modules/rolldown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.2.tgz", - "integrity": "sha512-opwpo1tQBAcpSUJDt94B7hhLNGOKjCdE//XXjeLrnx9b83bjnw45tXdg1b09yEw/VLFBJGZpwRULMmOZo7ol+A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz", + "integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==", "license": "MIT", "peer": true, "dependencies": { - "@oxc-project/types": "=0.142.0", + "@oxc-project/types": "=0.147.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -1280,20 +1297,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.2", - "@rolldown/binding-darwin-arm64": "1.2.2", - "@rolldown/binding-darwin-x64": "1.2.2", - "@rolldown/binding-freebsd-x64": "1.2.2", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.2", - "@rolldown/binding-linux-arm64-gnu": "1.2.2", - "@rolldown/binding-linux-arm64-musl": "1.2.2", - "@rolldown/binding-linux-ppc64-gnu": "1.2.2", - "@rolldown/binding-linux-s390x-gnu": "1.2.2", - "@rolldown/binding-linux-x64-gnu": "1.2.2", - "@rolldown/binding-linux-x64-musl": "1.2.2", - "@rolldown/binding-openharmony-arm64": "1.2.2", - "@rolldown/binding-win32-arm64-msvc": "1.2.2", - "@rolldown/binding-win32-x64-msvc": "1.2.2" + "@rolldown/binding-android-arm-eabi": "1.2.6", + "@rolldown/binding-android-arm64": "1.2.6", + "@rolldown/binding-darwin-arm64": "1.2.6", + "@rolldown/binding-darwin-x64": "1.2.6", + "@rolldown/binding-freebsd-x64": "1.2.6", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.6", + "@rolldown/binding-linux-arm64-gnu": "1.2.6", + "@rolldown/binding-linux-arm64-musl": "1.2.6", + "@rolldown/binding-linux-ppc64-gnu": "1.2.6", + "@rolldown/binding-linux-s390x-gnu": "1.2.6", + "@rolldown/binding-linux-x64-gnu": "1.2.6", + "@rolldown/binding-linux-x64-musl": "1.2.6", + "@rolldown/binding-openharmony-arm64": "1.2.6", + "@rolldown/binding-win32-arm64-msvc": "1.2.6", + "@rolldown/binding-win32-x64-msvc": "1.2.6" } }, "node_modules/siginfo": { @@ -1372,16 +1390,16 @@ } }, "node_modules/vite": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", - "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "license": "MIT", "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", - "postcss": "^8.5.23", - "rolldown": "~1.2.0", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", "tinyglobby": "^0.2.17" }, "bin": { @@ -1398,7 +1416,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -1450,19 +1468,19 @@ } }, "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "license": "MIT", "peer": true, "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -1490,12 +1508,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/vitest-accessibility-checker/src/package.json b/vitest-accessibility-checker/src/package.json index 01b9535f4..6270ae9be 100644 --- a/vitest-accessibility-checker/src/package.json +++ b/vitest-accessibility-checker/src/package.json @@ -37,10 +37,10 @@ "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", - "exceljs": "^4.4.0" + "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { - "exceljs": { + "write-excel-file": { "optional": true } }, From 826be74cf84ebd6c61a74d37bff73b628d9501d2 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 28 Aug 2026 16:29:41 -0500 Subject: [PATCH 02/12] exceljs error --- .github/workflows/master.yml | 4 ---- .github/workflows/publish.yml | 5 ----- .github/workflows/test.yml | 4 ---- accessibility-checker-extension/scripts/mozilla.sh | 5 ----- 4 files changed, 18 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 4b2594953..f08365aa5 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -35,10 +35,6 @@ jobs: working-directory: rule-server - run: npm run build working-directory: rule-server - - run: sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.js - working-directory: accessibility-checker-extension/node_modules/exceljs/dist - - run: sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.min.js - working-directory: accessibility-checker-extension/node_modules/exceljs/dist - run: cp -f ./manifest_Chrome.json ./src/manifest.json working-directory: accessibility-checker-extension - run: npm run package:browser diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f9cd24ae2..77c3a1b52 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -203,10 +203,6 @@ jobs: working-directory: rule-server - run: npm run build working-directory: rule-server - - run: sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.js - working-directory: accessibility-checker-extension/node_modules/exceljs/dist - - run: sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.min.js - working-directory: accessibility-checker-extension/node_modules/exceljs/dist - run: cp -f ./manifest_Chrome.json ./src/manifest.json working-directory: accessibility-checker-extension - run: | @@ -239,7 +235,6 @@ jobs: else EXT_VERSION="${NPM_VERSION}.9999" fi; - sed -i'.old' -e 's/"version": "3.0.0",/"version": "'"${EXT_VERSION}"'",/g' ./manifest.json fi; working-directory: accessibility-checker-extension/src - run: rm manifest.json.old diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d756242f3..4110def35 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -591,10 +591,6 @@ jobs: npm install npm run build working-directory: rule-server - - run: sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.js - working-directory: accessibility-checker-extension/node_modules/exceljs/dist - - run: sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.min.js - working-directory: accessibility-checker-extension/node_modules/exceljs/dist - run: cp -f ./manifest_Chrome.json ./src/manifest.json working-directory: accessibility-checker-extension - run: npm run package:browser diff --git a/accessibility-checker-extension/scripts/mozilla.sh b/accessibility-checker-extension/scripts/mozilla.sh index b844afc44..7dfe6139d 100755 --- a/accessibility-checker-extension/scripts/mozilla.sh +++ b/accessibility-checker-extension/scripts/mozilla.sh @@ -5,11 +5,6 @@ popd pushd accessibility-checker-extension npm install -pushd node_modules/exceljs/dist -sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.js -sed -i'.old' -e "s/[\"|']use strict[\"|']//g" ./exceljs.min.js -popd - cp -f ./manifest_Firefox.json ./src/manifest.json pushd src From 90425fc0f5c3483ae6c1eeb231d834924ca424e2 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 11:17:18 -0500 Subject: [PATCH 03/12] Fix colors / tables --- .../package-lock.json | 24 +- .../multiScanReport/xlsx/MultiScanReport.tsx | 2510 ++++------------- .../test/package-lock.json | 6 +- accessibility-checker/package.json | 2 +- accessibility-checker/src/README.md | 10 + common/module/package-lock.json | 10 +- common/module/package.json | 6 +- common/module/src/report/ACReporterXLSX.ts | 187 +- cypress-accessibility-checker/README.md | 6 +- .../boilerplates/package-lock.json | 12 +- .../package-lock.json | 18 +- karma-accessibility-checker/README.md | 6 +- report-react/package-lock.json | 83 +- rule-server/package-lock.json | 6 +- vitest-accessibility-checker/README.md | 10 + .../package-lock.json | 12 +- 16 files changed, 766 insertions(+), 2142 deletions(-) diff --git a/accessibility-checker-extension/package-lock.json b/accessibility-checker-extension/package-lock.json index 117671734..66006903d 100644 --- a/accessibility-checker-extension/package-lock.json +++ b/accessibility-checker-extension/package-lock.json @@ -4486,9 +4486,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.416", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", - "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", + "version": "1.5.417", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz", + "integrity": "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -5339,9 +5339,9 @@ } }, "node_modules/ip-address": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", - "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", + "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", "dev": true, "license": "MIT", "engines": { @@ -7045,9 +7045,9 @@ } }, "node_modules/serialize-javascript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.0.tgz", - "integrity": "sha512-RNEqWOyhhUQYN9V1GfHwu9AR/g+NTciH6Z5u3/no6X3/w+04J2lVDL+svFQVXgXrEGBMG2puMVN3gq2SNGuTGw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.1.tgz", + "integrity": "sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -8066,9 +8066,9 @@ "license": "MPL-2.0" }, "node_modules/webpack": { - "version": "5.110.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.1.tgz", - "integrity": "sha512-gInQB+jxXxgnZyvPwuzT5NGQmECDqeu85oxcrjinrYHqPoBex0hCAN2SFTJVyPVrK0Pq9E44VFP+e89fAc10/w==", + "version": "5.110.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.2.tgz", + "integrity": "sha512-TciLrfM7zgEjqGdY851HkirDsSPQgTFsWQpl9oHqMAMYsHhEC0bKjscvjpnz+pzx10hLC8qISApGrsnrCP4UtQ==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", diff --git a/accessibility-checker-extension/src/ts/util/xlsxReport/multiScanReport/xlsx/MultiScanReport.tsx b/accessibility-checker-extension/src/ts/util/xlsxReport/multiScanReport/xlsx/MultiScanReport.tsx index 7b604d2f2..ab553e056 100644 --- a/accessibility-checker-extension/src/ts/util/xlsxReport/multiScanReport/xlsx/MultiScanReport.tsx +++ b/accessibility-checker-extension/src/ts/util/xlsxReport/multiScanReport/xlsx/MultiScanReport.tsx @@ -15,2085 +15,535 @@ *****************************************************************************/ import ReportUtil from "../../reportUtil"; -// import ReportSummaryUtil from '../../../util/reportSummaryUtil'; - -import ExcelJS from "exceljs" +import writeExcelFile from "write-excel-file/browser"; +import { unzipSync, strFromU8, strToU8, zipSync } from "fflate"; import { IArchiveDefinition, IStoredReportMeta, StoredScanData } from "../../../../interfaces/interfaces"; +// ─── XLSX table injection ────────────────────────────────────────────────────── +// +// write-excel-file has no native Excel table API. We post-process the Blob it +// produces: unzip it with fflate (already a transitive dep), inject the table +// definition XML, wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// The table covers A1: where lastCol = "N" (14 columns). +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. + +const ISSUES_SHEET_ID = "4"; +const TABLE_ID = "1"; +const TABLE_COL_COUNT = 14; +const COL_LETTERS = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N"]; + +function colLetter(n: number): string { return COL_LETTERS[n - 1] ?? "A"; } + +function tableXml(rowCount: number): string { + const lastCol = colLetter(TABLE_COL_COUNT); + const ref = `A1:${lastCol}${rowCount}`; + const cols = [ + "Page title","Page URL","Scan label","Issue ID","Issue type", + "Toolkit level","Checkpoint","WCAG level","Rule","Issue", + "Element","Code","Xpath","Help", + ].map((name, i) => + `` + ).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} + +function tableRelsXml(): string { + return `` + + `` + + `` + + ``; +} + +async function injectTable(blob: Blob, issueRowCount: number): Promise { + // 1. Unzip + const arrayBuf = await blob.arrayBuffer(); + const files = unzipSync(new Uint8Array(arrayBuf)); + + // 2. Add xl/tables/table1.xml + files[`xl/tables/table${TABLE_ID}.xml`] = strToU8(tableXml(issueRowCount)); + + // 3. Patch (or create) xl/worksheets/_rels/sheet4.xml.rels to add the table relationship + const relsKey = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const existingRels = files[relsKey] ? strFromU8(files[relsKey]) : null; + if (existingRels && existingRels.includes("", + `` + + `` + )); + } else { + files[relsKey] = strToU8(tableRelsXml()); + } + + // 4. Patch xl/worksheets/sheet4.xml to add before + const sheetKey = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = strFromU8(files[sheetKey]); + files[sheetKey] = strToU8(sheetXml.replace( + "", + `` + )); + + // 5. Patch [Content_Types].xml to register the table XML content type + const ctKey = "[Content_Types].xml"; + const ctXml = strFromU8(files[ctKey]); + files[ctKey] = strToU8(ctXml.replace( + "", + `` + )); + + // 6. Re-zip and return as Blob + const zipped = zipSync(files); + return new Blob([zipped], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); +} + function perc(a: number, b: number) { return parseInt((((a) / b) * 100).toFixed(0)); } -export default class MultiScanReport { +// ─── Cell style helpers ──────────────────────────────────────────────────────── - public static async multiScanXlsxDownload(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]) { - // create workbook - let reportWorkbook = await MultiScanReport.generateWorkbook(storedScans, archives); +function hdr(value: any, extra: any = {}): any { + return { value, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", ...extra }; +} - // create binary buffer - const buffer = await reportWorkbook.xlsx.writeBuffer(); +function colHdr(value: any, bg: string, textColor = "#000000", extra: any = {}): any { + return { value, backgroundColor: bg, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "center", ...extra }; +} - // create xlsx blob - const fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; - const blob = new Blob([buffer], { type: fileType }); +function bd(value: any, extra: any = {}): any { + return { value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", ...extra }; +} - // const fileName = ReportUtil.single_page_report_file_name(xlsx_props.tab_title); - const fileName = ReportUtil.single_page_report_file_name(storedScans[storedScans.length - 1].pageTitle); +// ─── Sheet builders ──────────────────────────────────────────────────────────── - // download file - ReportUtil.download_file(blob, fileName); +function buildOverviewSheet(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]): any { + let violations = 0, needsReviews = 0, recommendations = 0, hidden = 0; + for (const s of storedScans) { + violations += (s.counts.Violation || 0); + needsReviews += (s.counts["Needs review"] || 0); + recommendations += (s.counts.Recommendation || 0); + hidden += (s.counts.Hidden || 0); } - - public static async generateWorkbook(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]) { - let msReport = new MultiScanReport(storedScans, archives); - return msReport.getWorkbook(); + const totalIssues = violations + needsReviews + recommendations; + const lastScan = storedScans[storedScans.length - 1]; + const uniqueURLs = new Set(storedScans.map(s => s.pageURL)).size; + + const columns = [ + { width: 15.1 }, { width: 15.9 }, { width: 16.23 }, { width: 19.4 }, { width: 15.9 } + ]; + + const rowMeta = [ + { key1: "Tool:", key2: "IBM Equal Access Accessibility Checker" }, + { key1: "Version:", key2: chrome.runtime.getManifest().version }, + // @ts-ignore + { key1: "Rule set:", key2: (lastScan.ruleset === "Latest Deployment") ? archives[1].name : lastScan.ruleset }, + { key1: "Guidelines:", key2: lastScan.guideline }, + { key1: "Report date:", key2: new Date(lastScan.timestamp) }, + { key1: "Platform:", key2: navigator.userAgent }, + { key1: "Scans:", key2: storedScans.length }, + { key1: "Pages:", key2: uniqueURLs }, + ]; + + const data: any[][] = []; + + // Row 1: title spanning 5 cols + data.push([hdr("Accessibility Scan Report", { height: 27, columnSpan: 5 }), null, null, null, null]); + + // Rows 2–9: metadata (key in col A, value spanning B–D) + for (let i = 0; i < rowMeta.length; i++) { + const h = i === 5 ? 36 : 12; // Platform row is taller + data.push([ + { value: rowMeta[i].key1, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: h }, + { value: rowMeta[i].key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", wrap: i === 5, columnSpan: 4 }, + null, null, null + ]); } - // @ts-ignore - private workbook = new ExcelJS.Workbook({ useStyles: true }); - - /** - * @param storedScans - * @param scanType - * @param storedScanCount - * @param archives - * @returns - */ - private constructor(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]) { - // create worksheets - this.createOverviewSheet(storedScans, archives); - this.createScanSummarySheet(storedScans); - this.createIssueSummarySheet(storedScans); - this.createIssuesSheet(storedScans); - this.createDefinitionsSheet(); - } + // Row 10: blank + data.push([null]); + + // Row 11: "Summary" title + data.push([hdr("Summary", { height: 27, columnSpan: 5 }), null, null, null, null]); + + // Row 12: column headers + data.push([ + colHdr("Issues", "#000000", "#FFFFFF", { height: 16 }), + colHdr("Violations", "#E4AAAF"), + colHdr("Needs review", "#F4E08A"), + colHdr("Recommendations", "#96A9D7"), + colHdr("Hidden", "#BFBFBF"), + ]); + + // Row 13: values + data.push([ + bd(totalIssues, { align: "center", height: 27 }), + bd(violations, { align: "center" }), + bd(needsReviews, { align: "center" }), + bd(recommendations, { align: "center" }), + bd(hidden, { align: "center" }), + ]); + + return { data, sheet: "Overview", columns }; +} - private getWorkbook() { - return this.workbook; +function buildScanSummarySheet(storedScans: IStoredReportMeta[]): any { + const columns = [ + { width: 27.0 }, { width: 46.0 }, { width: 20.17 }, { width: 18.5 }, + { width: 17.17 }, { width: 17.17 }, { width: 17.17 }, { width: 17.17 }, + { width: 17.17 }, { width: 17.17 }, + ]; + + const hBase = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + + const data: any[][] = []; + + data.push([ + { value: "Page title", ...hBase, align: "left" }, + { value: "Page url", ...hBase, align: "left" }, + { value: "Scan label", ...hBase, align: "left" }, + { value: "Base scan", ...hBase, align: "left" }, + colHdr("Violations", "#E4AAAF", "#000000", { height: 39 }), + colHdr("Needs review", "#F4E08A", "#000000", { height: 39 }), + colHdr("Recommendations", "#96A9D7", "#000000", { height: 39 }), + colHdr("Hidden", "#BFBFBF", "#000000", { height: 39 }), + colHdr("% elements without violations", "#000000", "#FFFFFF", { height: 39, wrap: true }), + colHdr("% elements without violations or items to review", "#000000", "#FFFFFF", { height: 39, wrap: true }), + ]); + + for (const storedScan of storedScans) { + const violations = storedScan.storedScanData.filter((r: StoredScanData) => r[4] === "Violation"); + const potentials = storedScan.storedScanData.filter((r: StoredScanData) => r[4] === "Needs review"); + const violationXpaths = violations.map((r: StoredScanData) => r[12]); + const reviewXpaths = potentials.map((r: StoredScanData) => r[12]); + const violationPlusPotentialXpaths = violationXpaths.concat(reviewXpaths); + const violationUniqueElements = new Set(violationXpaths).size; + const violationPlusPotentialUniqueElements = new Set(violationPlusPotentialXpaths).size; + const tested = (storedScan.testedUniqueElements || 0); + + const tStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const nStyle = { ...tStyle, align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }; + data.push([ + { value: storedScan.pageTitle, ...tStyle, align: "left" }, + { value: storedScan.pageURL, ...tStyle, align: "left" }, + { value: storedScan.label, ...tStyle, align: "left" }, + { value: "none", ...tStyle, align: "left" }, + { value: storedScan.counts["Violation"] || 0, ...nStyle }, + { value: storedScan.counts["Needs review"] || 0, ...nStyle }, + { value: storedScan.counts["Recommendation"]|| 0, ...nStyle }, + { value: storedScan.counts["Hidden"] || 0, ...nStyle }, + { value: perc(tested - violationUniqueElements, tested), ...nStyle }, + { value: perc(tested - violationPlusPotentialUniqueElements, tested), ...nStyle }, + ]); } - private createOverviewSheet(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]) { + return { data, sheet: "Scan summary", columns }; +} - let violations = 0; - let needsReviews = 0; - let recommendations = 0; - let hidden = 0; +// ─── Issue summary helpers ───────────────────────────────────────────────────── - for (const storedScan of storedScans) { - violations += (storedScan.counts.Violation || 0); - needsReviews += (storedScan.counts["Needs review"] || 0); - recommendations += (storedScan.counts.Recommendation || 0); - hidden += (storedScan.counts.Hidden || 0); - } - let totalIssues = violations + needsReviews + recommendations; - - let lastScan = storedScans[storedScans.length - 1]; - const worksheet = this.workbook.addWorksheet("Overview"); - - // Report Title - worksheet.mergeCells('A1', "E1"); - const titleRow = worksheet.getRow(1); - titleRow.height = 27; - - const cellA1 = worksheet.getCell('A1'); - cellA1.value = "Accessibility Scan Report"; - cellA1.alignment = { vertical: "middle", horizontal: "left" }; - cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - // what are column widths - can't get it till you set it - const colWidthData = [ - { col: 'A', width: 15.1 }, - { col: 'B', width: 15.9 }, - { col: 'C', width: 16.23 }, - { col: 'D', width: 19.4 }, - { col: 'E', width: 15.9 }, - ] - - for (let i = 0; i < 5; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } +type IssueDef = { issueDef: string; hidden: boolean }; - - // set row height for rows 2-10 - for (let i = 2; i < 11; i++) { - if (i == 7) { - worksheet.getRow(i).height = 36; - } else { - worksheet.getRow(i).height = 12; // results in a row height of 16 - } +function countDuplicatesInArray(array: IssueDef[]): { [key: string]: [number, number] } { + const dup: { [k: string]: number } = {}; + const hid: { [k: string]: number } = {}; + for (const item of array) { + if (!item.hidden) { + dup[item.issueDef] = (dup[item.issueDef] || 0) + 1; + hid[item.issueDef] = (hid[item.issueDef] || 0); + } else { + dup[item.issueDef] = (dup[item.issueDef] || 0); + hid[item.issueDef] = (hid[item.issueDef] || 0) + 1; } + } + const final: { [k: string]: [number, number] } = {}; + for (const k of Object.keys({ ...dup, ...hid })) { + final[k] = [dup[k] || 0, hid[k] || 0]; + } + return final; +} - let uniqueURLs = new Set(storedScans.map(scan => scan.pageURL)).size; - - // note except for Report Date this is the same for all scans - const rowData = [ - { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, - { key1: 'Version:', key2: chrome.runtime.getManifest().version }, - //@ts-ignore - { key1: 'Rule set:', key2: (lastScan.ruleset === "Latest Deployment") ? archives[1].name : lastScan.ruleset }, - { key1: 'Guidelines:', key2: lastScan.guideline }, - { key1: 'Report date:', key2: new Date(lastScan.timestamp) }, // do we need to get actual date? - { key1: 'Platform:', key2: navigator.userAgent }, - { key1: 'Scans:', key2: storedScans.length }, // *** NEED TO FIX FOR selected - { key1: 'Pages:', key2: uniqueURLs } - ]; - - worksheet.mergeCells('B2', "D2"); - worksheet.mergeCells('B3', "D3"); - worksheet.mergeCells('B4', "D4"); - worksheet.mergeCells('B5', "D5"); - worksheet.mergeCells('B6', "D6"); - worksheet.mergeCells('B7', "D7"); - worksheet.mergeCells('B8', "D8"); - worksheet.mergeCells('B9', "D9"); - worksheet.mergeCells('A10', "D10"); - - - for (let i = 2; i < 10; i++) { - worksheet.getRow(i).getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(1).alignment = { horizontal: "left" }; - worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" }; - if (i == 7) { - worksheet.getRow(i).getCell(1).alignment = { vertical: "top" }; - worksheet.getRow(i).getCell(2).alignment = { wrapText: true }; - } - } - for (let i = 2; i < 10; i++) { - worksheet.getRow(i).getCell(1).value = rowData[i - 2].key1; worksheet.getRow(i).getCell(2).value = rowData[i - 2].key2; - } +function levelSubRows(bg: string, textColor: string, label: string, + count: number, hiddenCount: number, + rowValues: { [k: string]: [number, number] }): any[][] { + const rows: any[][] = []; + + // Sub-header row + rows.push([ + { value: ` ${label}`, backgroundColor: bg, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: count, backgroundColor: bg, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + { value: hiddenCount, backgroundColor: bg, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "center" }, + ]); + + // Individual issue rows sorted desc by visible count + const sorted = Object.entries(rowValues).sort((a, b) => b[1][0] - a[1][0]); + for (const [msg, [vis, hid]] of sorted) { + rows.push([ + { value: " " + msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: vis, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + { value: hid, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "center" }, + ]); + } + return rows; +} - // Summary Title - worksheet.mergeCells('A11', "E11"); +function levelRows(title: string, counts: number[], + V: IssueDef[], NR: IssueDef[], R: IssueDef[]): any[][] { + const rows: any[][] = []; + const hiddenCount = counts[4]; - const summaryRow = worksheet.getRow(11); - summaryRow.height = 27; + // Level header row + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: counts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + { value: hiddenCount, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }, + ]); - const cellA11 = worksheet.getCell('A11'); - cellA11.value = "Summary"; - cellA11.alignment = { vertical: "middle", horizontal: "left" }; - cellA11.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA11.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; + const vValues = countDuplicatesInArray(V); + const nrValues = countDuplicatesInArray(NR); + const rValues = countDuplicatesInArray(R); - // Scans info Headers - worksheet.getRow(12).height = 16; // actual height is + const hiddenV = Object.values(vValues).reduce((s, [,h]) => s + h, 0); + const hiddenNR = Object.values(nrValues).reduce((s, [,h]) => s + h, 0); + const hiddenR = Object.values(rValues).reduce((s, [,h]) => s + h, 0); - const cellA12 = worksheet.getCell('A12'); cellA12.value = "Issues"; - const cellB12 = worksheet.getCell('B12'); cellB12.value = "Violations"; - const cellC12 = worksheet.getCell('C12'); cellC12.value = "Needs review"; - const cellD12 = worksheet.getCell('D12'); cellD12.value = "Recommendations"; - const cellE12 = worksheet.getCell('E12'); cellE12.value = "Hidden"; + rows.push(...levelSubRows("#E4AAAF", "#000000", "Violation", counts[1], hiddenV, vValues)); + rows.push(...levelSubRows("#F4E08A", "#000000", "Needs review", counts[2], hiddenNR, nrValues)); + rows.push(...levelSubRows("#96A9D7", "#000000", "Recommendation",counts[3], hiddenR, rValues)); - const cellObjects1 = [cellA12, cellB12, cellC12, cellD12, cellE12]; + return rows; +} - for (let i = 0; i < 5; i++) { - cellObjects1[i].alignment = { vertical: "middle", horizontal: "center" }; - if (i == 1 || i == 2 || i == 3 || i == 4) { - cellObjects1[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - } else { - cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - } +function buildIssueSummarySheet(storedScans: IStoredReportMeta[]): any { + const columns = [{ width: 155.51 }, { width: 21.16 }, { width: 18.0 }]; - // cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} }; - cellObjects1[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } + const lvl = [1,2,3,4].map(() => ({ counts: [0,0,0,0,0], V: [] as IssueDef[], NR: [] as IssueDef[], R: [] as IssueDef[] })); - cellA12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - cellB12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - cellC12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - cellD12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - cellE12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFBFBFBF' } }; - - - // Scans info Values - worksheet.getRow(13).height = 27; // actual height is - - const cellA13 = worksheet.getCell('A13'); cellA13.value = totalIssues; - const cellB13 = worksheet.getCell('B13'); cellB13.value = violations; - const cellC13 = worksheet.getCell('C13'); cellC13.value = needsReviews; - const cellD13 = worksheet.getCell('D13'); cellD13.value = recommendations; - const cellE13 = worksheet.getCell('E13'); cellE13.value = hidden; - - const cellObjects2 = [cellA13, cellB13, cellC13, cellD13, cellE13]; - - for (let i = 0; i < 5; i++) { - cellObjects2[i].alignment = { vertical: "middle", horizontal: "center" }; - cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - cellObjects2[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } + for (const storedScan of storedScans) { + for (const row of storedScan.storedScanData) { + const lv = row[5]; + if (lv < 1 || lv > 4) continue; + const L = lvl[lv - 1]; + const isHidden = !!row[14]; + if (!isHidden) L.counts[0]++; + if (row[4] === "Violation") { if (!isHidden) L.counts[1]++; L.V.push({issueDef: row[9], hidden: isHidden}); } + if (row[4] === "Needs review") { if (!isHidden) L.counts[2]++; L.NR.push({issueDef: row[9], hidden: isHidden}); } + if (row[4] === "Recommendation"){ if (!isHidden) L.counts[3]++; L.R.push({issueDef: row[9], hidden: isHidden}); } + if (isHidden) L.counts[4]++; } } - private createScanSummarySheet(storedScans: IStoredReportMeta[]) { - - const worksheet = this.workbook.addWorksheet("Scan summary"); - - // Scans info Headers - worksheet.getRow(1).height = 39; // actual height is 52 - - const colWidthData = [ - { col: 'A', width: 27.0 }, - { col: 'B', width: 46.0 }, - { col: 'C', width: 20.17 }, - { col: 'D', width: 18.5 }, - { col: 'E', width: 17.17 }, - { col: 'F', width: 17.17 }, - { col: 'G', width: 17.17 }, - { col: 'H', width: 17.17 }, - { col: 'I', width: 17.17 }, - { col: 'J', width: 17.17 }, - ] - - for (let i = 0; i < 10; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } - - const cellA1 = worksheet.getCell('A1'); cellA1.value = "Page title"; - const cellB1 = worksheet.getCell('B1'); cellB1.value = "Page url"; - const cellC1 = worksheet.getCell('C1'); cellC1.value = "Scan label"; - const cellD1 = worksheet.getCell('D1'); cellD1.value = "Base scan"; - - const cellObjects1 = [cellA1, cellB1, cellC1, cellD1]; - - for (let i = 0; i < 4; i++) { - cellObjects1[i].alignment = { vertical: "middle", horizontal: "left" }; - cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - cellObjects1[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } - - const cellE1 = worksheet.getCell('E1'); cellE1.value = "Violations"; - const cellF1 = worksheet.getCell('F1'); cellF1.value = "Needs review"; - const cellG1 = worksheet.getCell('G1'); cellG1.value = "Recommendations"; - const cellH1 = worksheet.getCell('H1'); cellH1.value = "Hidden"; - const cellI1 = worksheet.getCell('I1'); cellI1.value = "% elements without violations"; - const cellJ1 = worksheet.getCell('J1'); cellJ1.value = "% elements without violations or items to review"; - - const cellObjects2 = [cellE1, cellF1, cellG1, cellH1, cellI1, cellJ1]; - - for (let i = 0; i < 6; i++) { - cellObjects2[i].alignment = { vertical: "middle", horizontal: "center", wrapText: true }; - if (i == 0 || i == 1 || i == 2 || i == 3) { - cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - } else { - cellObjects2[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - } + const totalIssues = lvl.reduce((s, l) => s + l.counts[0], 0); + const totalHidden = lvl.reduce((s, l) => s + l.counts[4], 0); + + const data: any[][] = []; + + // Row 1: title + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 3 }, + null, null + ]); + + // Row 2: description + column headers + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into four levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20 }, + { value: "Issues", backgroundColor: "#E3E3E3", textColor: "#000000", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + { value: "Hidden issues", backgroundColor: "#E3E3E3", textColor: "#000000", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "center" }, + ]); + + // Row 3: totals + data.push([ + { value: "Issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + { value: totalHidden, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }, + ]); + + // Row 4: blank header row with "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + null, null + ]); + + // Levels 1–4 + const titles = [ + "Level 1 - the most essential issues to address", + "Level 2 - the next most important issues", + "Level 3 - necessary to meet requirements", + "Level 4 - further recommended improvements to accessibility", + ]; + for (let i = 0; i < 4; i++) { + data.push(...levelRows(titles[i], lvl[i].counts, lvl[i].V, lvl[i].NR, lvl[i].R)); + } - // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} }; - cellObjects2[i].border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } + return { data, sheet: "Issue summary", columns }; +} - cellE1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - cellF1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - cellG1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - cellH1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFBFBFBF' } }; - cellI1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - cellJ1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - - - // if current scan use last scan, if - // if current scan use only the last scan otherwise loop through each scan an create row - for (const storedScan of storedScans) { - // JCH find unique elements that have violations and needs review issues - let violations = storedScan && storedScan.storedScanData.filter((result: StoredScanData) => { - return result[4] === "Violation"; - }) || [] - - let potentials = storedScan && storedScan.storedScanData.filter((result: StoredScanData) => { - return result[4] === "Needs review"; - }) || [] - - let violationXpaths: string[] = violations.map(result => result[12]); - let reviewXpaths: string[] = potentials.map(result => result[12]); - let violationPlusPotentialXpaths = violationXpaths.concat(reviewXpaths); - let violationUniqueElements = new Set(violationXpaths).size; - let violationPlusPotentialUniqueElements = new Set(violationPlusPotentialXpaths).size; - let testedElements = (storedScan && storedScan.testedUniqueElements || 0); - - let row = worksheet.addRow( - [storedScan.pageTitle, - storedScan.pageURL, - storedScan.label, - "none", - storedScan.counts["Violation"], - storedScan.counts["Needs review"], - storedScan.counts["Recommendation"], - storedScan.counts["Hidden"], - perc(testedElements-violationUniqueElements, testedElements), - perc(testedElements-violationPlusPotentialUniqueElements, testedElements) +function buildIssuesSheet(storedScans: IStoredReportMeta[]): any { + const columns = [ + { width: 18.0 }, { width: 20.5 }, { width: 21.0 }, { width: 18.5 }, + { width: 23.0 }, { width: 17.17 }, { width: 17.17 }, { width: 17.17 }, + { width: 17.17 }, { width: 17.17 }, { width: 14.0 }, { width: 17.17 }, + { width: 43.0 }, { width: 17.17 }, + ]; + + const hStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", align: "center", alignVertical: "center", wrap: true, height: 24 }; + + const data: any[][] = []; + + data.push([ + { value: "Page title", ...hStyle }, + { value: "Page URL", ...hStyle }, + { value: "Scan label", ...hStyle }, + { value: "Issue ID", ...hStyle }, + { value: "Issue type", ...hStyle }, + { value: "Toolkit level", ...hStyle }, + { value: "Checkpoint", ...hStyle }, + { value: "WCAG level", ...hStyle }, + { value: "Rule", ...hStyle }, + { value: "Issue", ...hStyle }, + { value: "Element", ...hStyle }, + { value: "Code", ...hStyle }, + { value: "Xpath", ...hStyle }, + { value: "Help", ...hStyle }, + ]); + + for (const storedScan of storedScans) { + for (const r of storedScan.storedScanData) { + const dStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", height: 14, alignVertical: "center" }; + data.push([ + { value: r[0], ...dStyle, align: "left" }, + { value: r[1], ...dStyle, align: "left" }, + { value: storedScan.label, ...dStyle, align: "center" }, + { value: r[3], ...dStyle, align: "left" }, + { value: r[14] ? "Hidden:" + r[4] : r[4], ...dStyle, align: "center" }, + { value: Number.isNaN(r[5]) ? "n/a" : r[5], ...dStyle, align: "center" }, + { value: r[6], ...dStyle, align: "left" }, + { value: Number.isNaN(r[5]) ? "n/a" : r[7], ...dStyle, align: "center" }, + { value: r[8], ...dStyle, align: "left" }, + { value: r[9], ...dStyle, align: "left" }, + { value: r[10], ...dStyle, align: "center" }, + { value: r[11], ...dStyle, align: "left" }, + { value: r[12], ...dStyle, align: "left" }, + { value: r[13], ...dStyle, align: "left" }, ]); - row.height = 37; // actual height is - for (let i = 1; i < 5; i++) { - row.getCell(i).alignment = { vertical: "middle", horizontal: "left", wrapText: true }; - row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 }; - } - for (let i = 5; i < 11; i++) { - row.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true }; - row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 }; - // row.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - row.getCell(i).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } } } - private createIssueSummarySheet(storedScans: IStoredReportMeta[]) { - - // let violations = 0; - // let needsReviews = 0; - // let recommendations = 0; - // let hidden = 0; - // let totalIssues = 0; - - // for (const scan of storedScans) { - // violations += scan.counts["Violation"]; - // needsReviews += scan.counts["Needs review"]; - // recommendations += scan.counts.Recommendation; - // hidden += scan.counts.Hidden; - // } - // totalIssues = violations + needsReviews + recommendations; - - // counts - let level1Counts = [0, 0, 0, 0, 0]; // level 1 total issues, violations, needs reviews, recommendations, hidden - let level2Counts = [0, 0, 0, 0, 0]; - let level3Counts = [0, 0, 0, 0, 0]; - let level4Counts = [0, 0, 0, 0, 0]; - let level1V: {issueDef:string, hidden:boolean}[] = []; let level2V: {issueDef:string, hidden:boolean}[] = []; let level3V: {issueDef:string, hidden:boolean}[] = []; let level4V: {issueDef:string, hidden:boolean}[] = []; - let level1NR: {issueDef:string, hidden:boolean}[] = []; let level2NR: {issueDef:string, hidden:boolean}[] = []; let level3NR: {issueDef:string, hidden:boolean}[] = []; let level4NR: {issueDef:string, hidden:boolean}[] = []; - let level1R: {issueDef:string, hidden:boolean}[] = []; let level2R: {issueDef:string, hidden:boolean}[] = []; let level3R: {issueDef:string, hidden:boolean}[] = []; let level4R: {issueDef:string, hidden:boolean}[] = []; - for (const storedScan of storedScans) { - const myStoredData = storedScan.storedScanData; - for (let i = 0; i < myStoredData.length; i++) { // for each issue row - if (myStoredData[i][5] == 1) { // if level 1 - if (!myStoredData[i][14]) { - level1Counts[0]++; // Level 1 issue count - } - if (myStoredData[i][4] === "Violation") { - if (!myStoredData[i][14]) { - level1Counts[1]++; - } - level1V.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Needs review") { - if (!myStoredData[i][14]) { - level1Counts[2]++; - } - level1NR.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Recommendation") { - if (!myStoredData[i][14]) { - level1Counts[3]++; - } - level1R.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][14] === true) { // we have a level 1 hidden - level1Counts[4]++; - } - } - if (myStoredData[i][5] == 2) { // if level 2 - if (!myStoredData[i][14]) { - level2Counts[0]++; - } - if (myStoredData[i][4] === "Violation") { - if (!myStoredData[i][14]) { - level2Counts[1]++; - } - level2V.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Needs review") { - if (!myStoredData[i][14]) { - level2Counts[2]++; - } - level2NR.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Recommendation") { - if (!myStoredData[i][14]) { - level2Counts[3]++; - } - level2R.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][14] === true) { // we have a level 2 hidden - level2Counts[4]++; - } - } - if (myStoredData[i][5] == 3) { // if level 3 - if (!myStoredData[i][14]) { - level3Counts[0]++; - } - if (myStoredData[i][4] === "Violation") { - if (!myStoredData[i][14]) { - level3Counts[1]++; - } - level3V.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Needs review") { - if (!myStoredData[i][14]) { - level3Counts[2]++; - } - level3NR.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Recommendation") { - if (!myStoredData[i][14]) { - level3Counts[3]++; - } - level3R.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][14] === true) { // we have a level 3 hidden - level3Counts[4]++; - } - } - if (myStoredData[i][5] == 4) { // if level 4 - if (!myStoredData[i][14]) { - level4Counts[0]++; - } - if (myStoredData[i][4] === "Violation") { - if (!myStoredData[i][14]) { - level4Counts[1]++; - } - level4V.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Needs review") { - if (!myStoredData[i][14]) { - level4Counts[2]++; - } - level4NR.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][4] === "Recommendation") { - if (!myStoredData[i][14]) { - level4Counts[3]++; - } - level4R.push({"issueDef":myStoredData[i][9], "hidden":myStoredData[i][14]}); - } - if (myStoredData[i][14] === true) { // we have a level 4 hidden - level4Counts[4]++; - } - } - } - } - - let level1VrowValues = MultiScanReport.countDuplicatesInArray(level1V); // note this returns an object - let level1NRrowValues = MultiScanReport.countDuplicatesInArray(level1NR); - let level1RrowValues = MultiScanReport.countDuplicatesInArray(level1R); - - let level2VrowValues = MultiScanReport.countDuplicatesInArray(level2V); // note this returns an object - let level2NRrowValues = MultiScanReport.countDuplicatesInArray(level2NR); - let level2RrowValues = MultiScanReport.countDuplicatesInArray(level2R); - - let level3VrowValues = MultiScanReport.countDuplicatesInArray(level3V); // note this returns an object - let level3NRrowValues = MultiScanReport.countDuplicatesInArray(level3NR); - let level3RrowValues = MultiScanReport.countDuplicatesInArray(level3R); - - let level4VrowValues = MultiScanReport.countDuplicatesInArray(level4V); // note this returns an object - let level4NRrowValues = MultiScanReport.countDuplicatesInArray(level4NR); - let level4RrowValues = MultiScanReport.countDuplicatesInArray(level4R); - - let totalIssues = level1Counts[0]+level2Counts[0]+level3Counts[0]+level4Counts[0]; - let hidden = level1Counts[4]+level2Counts[4]+level3Counts[4]+level4Counts[4]; - - const worksheet = this.workbook.addWorksheet("Issue summary"); - - // Approach: - // 1. sort by levels - // 2. for each level sort by V, NR and R - // 3. for each V, NR, and R in a level get issue dup counts - // 4. build the rows - - // build Issue summary title - worksheet.mergeCells('A1', 'B1', 'C1'); - - const titleRow = worksheet.getRow(1); - titleRow.height = 27; // actual is 36 - - const cellA1 = worksheet.getCell('A1'); - cellA1.value = "Issue summary"; - cellA1.alignment = { vertical: "middle", horizontal: "left" }; - cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - const cellC1 = worksheet.getCell('C1'); - cellC1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - const colWidthData = [ - { col: 'A', width: 155.51 }, // note .84 added to actual width - { col: 'B', width: 21.16 }, - { col: 'C', width: 18.00 }, - ] - - for (let i = 0; i < 3; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } - - // build Description title - // worksheet.mergeCells('A2', 'B2'); - - const descriptionRow = worksheet.getRow(2); - descriptionRow.height = 20.25; // actual is 27 - - const cellA2 = worksheet.getCell("A2"); - cellA2.value = " In the IBM Equal Access Toolkit, issues are divided into four levels (1-3). Tackle the levels in order to address some of the most impactful issues first."; - cellA2.alignment = { vertical: "middle", horizontal: "left" }; - cellA2.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellA2.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFFFF' } }; - - const cellB2 = worksheet.getCell("B2"); - cellB2.value = "Issues"; - cellB2.alignment = { vertical: "middle", horizontal: "right" }; - cellB2.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellB2.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE3E3E3' } }; - cellB2.border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - const cellC2 = worksheet.getCell("C2"); - cellC2.value = "Hidden issues"; - cellC2.alignment = { vertical: "middle", horizontal: "center" }; - cellC2.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellC2.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE3E3E3' } }; - cellC2.border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - const totalIssuesRow = worksheet.getRow(3); - totalIssuesRow.height = 27; // actual is 36 - - const cellA3 = worksheet.getCell("A3"); - cellA3.value = "Issues found:"; - cellA3.alignment = { vertical: "middle", horizontal: "left" }; - cellA3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - - const cellB3 = worksheet.getCell("B3"); - cellB3.value = totalIssues; - cellB3.alignment = { vertical: "middle", horizontal: "right" }; - cellB3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellB3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - - const cellC3 = worksheet.getCell("C3"); - cellC3.value = hidden; - cellC3.alignment = { vertical: "middle", horizontal: "center" }; - cellC3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellC3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } }; - cellC3.border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // build Number of issues title - const numberOfIssuesRow = worksheet.getRow(4); - numberOfIssuesRow.height = 20.25; // actual is 27 - - - const cellA4 = worksheet.getCell("A4"); - // no value - cellA4.alignment = { vertical: "middle", horizontal: "left" }; - cellA4.border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFFFFFFF' } } - }; - - - - - - ///////////////////////////// - // build Level 1 title - ///////////////////////////// - - const level1Row = worksheet.getRow(5); - level1Row.height = 27; // actual is 36 - - const cellA5 = worksheet.getCell("A5"); - cellA5.value = "Level 1 - the most essential issues to address"; - cellA5.alignment = { vertical: "middle", horizontal: "left" }; - cellA5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellA5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - const cellB5 = worksheet.getCell("B5"); - cellB5.value = level1Counts[0]; // total Level 1 issues - cellB5.alignment = { vertical: "middle", horizontal: "right" }; - cellB5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellB5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - const cellC5 = worksheet.getCell("C5"); - cellC5.value = level1Counts[4]; // Level 1 hidden counts - cellC5.alignment = { vertical: "middle", horizontal: "center" }; - cellC5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - cellC5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - cellC5.border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 1 Violation title - const level1ViolationRow = worksheet.getRow(6); - level1ViolationRow.height = 18; // target is 21 - - const cellA6 = worksheet.getCell("A6"); - cellA6.value = " Violation"; - cellA6.alignment = { vertical: "middle", horizontal: "left" }; - cellA6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellA6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level1ViolationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - const cellB6 = worksheet.getCell("B6"); - cellB6.value = level1Counts[1]; // total level 1 violations - cellB6.alignment = { vertical: "middle", horizontal: "right" }; - cellB6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellB6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level1ViolationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 1 violations - let level1HiddenVCounts = 0; - for (const property in level1VrowValues) { - level1HiddenVCounts += level1VrowValues[property][1]; - } - - const cellC6 = worksheet.getCell("C6"); - cellC6.value = level1HiddenVCounts; // hidden level 1 violations - cellC6.alignment = { vertical: "middle", horizontal: "center" }; - cellC6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - cellC6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level1ViolationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 1 Violation Rows - - // build rows - let rowArray = []; - - for (const property in level1VrowValues) { - let row = [" " + `${property}`, parseInt(`${level1VrowValues[property][0]}`), parseInt(`${level1VrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - - // add array of rows - - let rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - - // Level 1 Needs review title - const level1NeedsReviewRow = worksheet.addRow(["", 0]); - level1NeedsReviewRow.height = 18; // target is 21 - - level1NeedsReviewRow.getCell(1).value = " Needs review"; - level1NeedsReviewRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level1NeedsReviewRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level1NeedsReviewRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level1NeedsReviewRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level1NeedsReviewRow.getCell(2).value = level1Counts[2]; // total level 1 needs review - level1NeedsReviewRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level1NeedsReviewRow.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level1NeedsReviewRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level1NeedsReviewRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 1 needs review - let level1HiddenNRCounts = 0; - for (const property in level1NRrowValues) { - level1HiddenNRCounts += level1NRrowValues[property][1]; - } - - level1NeedsReviewRow.getCell(3).value = level1HiddenNRCounts; // hidden level 1 needs review - level1NeedsReviewRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level1NeedsReviewRow.getCell(3).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level1NeedsReviewRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level1NeedsReviewRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 1 Needs review Rows - - // build rows - rowArray = []; - - for (const property in level1NRrowValues) { - let row = [" " + `${property}`, parseInt(`${level1NRrowValues[property][0]}`), parseInt(`${level1NRrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - // Level 1 Recommendation title - const level1RecommendationRow = worksheet.addRow(["", 0]); - level1RecommendationRow.height = 18; // target is 21 - - level1RecommendationRow.getCell(1).value = " Recommendation"; - level1RecommendationRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level1RecommendationRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level1RecommendationRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level1RecommendationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level1RecommendationRow.getCell(2).value = level1Counts[3]; // total level 1 recommendations - level1RecommendationRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level1RecommendationRow.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level1RecommendationRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level1RecommendationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 1 recommendations - let level1HiddenRCounts = 0; - for (const property in level1RrowValues) { - level1HiddenRCounts += level1RrowValues[property][1]; - } - - level1RecommendationRow.getCell(3).value = level1HiddenRCounts; // hidden level 1 recommendations - level1RecommendationRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level1RecommendationRow.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level1RecommendationRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level1RecommendationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - - // Level 1 Recommendation Rows - - // build rows - rowArray = []; - - for (const property in level1RrowValues) { - let row = [" " + `${property}`, parseInt(`${level1RrowValues[property][0]}`), parseInt(`${level1RrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - - ///////////////////////////// - // build Level 2 title - ///////////////////////////// - - const level2Row = worksheet.addRow(["", 0]); - level2Row.height = 27; // actual is 36 - - level2Row.getCell(1).value = "Level 2 - the next most important issues"; - level2Row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level2Row.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level2Row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - level2Row.getCell(2).value = level2Counts[0]; // total Level 2 issues - level2Row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level2Row.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level2Row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - level2Row.getCell(3).value = level2Counts[4]; // Level 2 hidden counts - level2Row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level2Row.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level2Row.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - level2Row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - - // Level 2 Violation title - const level2ViolationRow = worksheet.addRow(["", 0]); - level2ViolationRow.height = 18; // target is 21 - - level2ViolationRow.getCell(1).value = " Violation"; - level2ViolationRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level2ViolationRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level2ViolationRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level2ViolationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level2ViolationRow.getCell(2).value = level2Counts[1]; // total level 2 violations - level2ViolationRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level2ViolationRow.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level2ViolationRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level2ViolationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 2 violations - let level2HiddenVCounts = 0; - for (const property in level2VrowValues) { - level2HiddenVCounts += level2VrowValues[property][1]; - } - - level2ViolationRow.getCell(3).value = level2HiddenVCounts; // hidden level 2 violations - level2ViolationRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level2ViolationRow.getCell(3).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level2ViolationRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level2ViolationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 2 Violation Rows - - // build rows - rowArray = []; - - for (const property in level2VrowValues) { - let row = [" " + `${property}`, parseInt(`${level2VrowValues[property][0]}`), parseInt(`${level2VrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - - // Level 2 Needs review title - const level2NeedsReviewRow = worksheet.addRow(["", 0]); - level2NeedsReviewRow.height = 18; // target is 21 - - level2NeedsReviewRow.getCell(1).value = " Needs review"; - level2NeedsReviewRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level2NeedsReviewRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level2NeedsReviewRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level2NeedsReviewRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level2NeedsReviewRow.getCell(2).value = level2Counts[2]; // total level 2 needs review - level2NeedsReviewRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level2NeedsReviewRow.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level2NeedsReviewRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level2NeedsReviewRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 2 needs review - let level2HiddenNRCounts = 0; - for (const property in level2NRrowValues) { - level2HiddenNRCounts += level2NRrowValues[property][1]; - } - - level2NeedsReviewRow.getCell(3).value = level2HiddenNRCounts; // hidden level 2 needs review - level2NeedsReviewRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level2NeedsReviewRow.getCell(3).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level2NeedsReviewRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level2NeedsReviewRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 2 Needs review Rows - - // build rows - rowArray = []; - - for (const property in level2NRrowValues) { - let row = [" " + `${property}`, parseInt(`${level2NRrowValues[property][0]}`), parseInt(`${level2NRrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - // Level 2 Recommendation title - const level2RecommendationRow = worksheet.addRow(["", 0]); - level2RecommendationRow.height = 18; // target is 21 - - level2RecommendationRow.getCell(1).value = " Recommendation"; - level2RecommendationRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level2RecommendationRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level2RecommendationRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level2RecommendationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level2RecommendationRow.getCell(2).value = level2Counts[3]; // total level 2 recommendations - level2RecommendationRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level2RecommendationRow.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level2RecommendationRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level2RecommendationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 2 recommendations - let level2HiddenRCounts = 0; - for (const property in level2RrowValues) { - level2HiddenRCounts += level2RrowValues[property][1]; - } - - level2RecommendationRow.getCell(3).value = level2HiddenRCounts; // hidden level 2 recommendations - level2RecommendationRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level2RecommendationRow.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level2RecommendationRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level2RecommendationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 2 Recommendation Rows - - // build rows - rowArray = []; - - for (const property in level2RrowValues) { - let row = [" " + `${property}`, parseInt(`${level2RrowValues[property][0]}`), parseInt(`${level2RrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - //row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - //row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - ///////////////////////////// - // build Level 3 title - ///////////////////////////// - - const level3Row = worksheet.addRow(["", 0]); - level3Row.height = 27; // actual is 36 - - level3Row.getCell(1).value = "Level 3 - necessary to meet requirements"; - level3Row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level3Row.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level3Row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - level3Row.getCell(2).value = level3Counts[0]; // total Level 3 issues - level3Row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level3Row.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level3Row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - level3Row.getCell(3).value = level3Counts[4]; // Level 1 hidden counts - level3Row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level3Row.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level3Row.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - level3Row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 3 Violation title - const level3ViolationRow = worksheet.addRow(["", 0]); - level3ViolationRow.height = 18; // target is 21 - - level3ViolationRow.getCell(1).value = " Violation"; - level3ViolationRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level3ViolationRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level3ViolationRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level3ViolationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level3ViolationRow.getCell(2).value = level3Counts[1]; // total level 3 violations - level3ViolationRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level3ViolationRow.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level3ViolationRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level3ViolationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 3 violations - let level3HiddenVCounts = 0; - for (const property in level3VrowValues) { - level3HiddenVCounts += level3VrowValues[property][1]; - } - - level3ViolationRow.getCell(3).value = level3HiddenVCounts; // hidden level 3 violations - level3ViolationRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level3ViolationRow.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level3ViolationRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level3ViolationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 3 Violation Rows - - // build rows - rowArray = []; - - for (const property in level3VrowValues) { - let row = [" " + `${property}`, parseInt(`${level3VrowValues[property][0]}`), parseInt(`${level3VrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - - // Level 3 Needs review title - const level3NeedsReviewRow = worksheet.addRow(["", 0]); - level3NeedsReviewRow.height = 18; // target is 21 - - level3NeedsReviewRow.getCell(1).value = " Needs review"; - level3NeedsReviewRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level3NeedsReviewRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level3NeedsReviewRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level3NeedsReviewRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level3NeedsReviewRow.getCell(2).value = level3Counts[2]; // total level 3 needs review - level3NeedsReviewRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level3NeedsReviewRow.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level3NeedsReviewRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level3NeedsReviewRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 3 needs review - let level3HiddenNRCounts = 0; - for (const property in level3NRrowValues) { - level3HiddenNRCounts += level3NRrowValues[property][1]; - } - - level3NeedsReviewRow.getCell(3).value = level3HiddenNRCounts; // hidden level 3 needs review - level3NeedsReviewRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level3NeedsReviewRow.getCell(3).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level3NeedsReviewRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level3NeedsReviewRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 3 Needs review Rows - - // build rows - rowArray = []; - - for (const property in level3NRrowValues) { - let row = [" " + `${property}`, parseInt(`${level3NRrowValues[property][0]}`), parseInt(`${level3NRrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - // Level 3 Recommendation title - const level3RecommendationRow = worksheet.addRow(["", 0]); - level3RecommendationRow.height = 18; // target is 21 - - level3RecommendationRow.getCell(1).value = " Recommendation"; - level3RecommendationRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level3RecommendationRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level3RecommendationRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level3RecommendationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level3RecommendationRow.getCell(2).value = level3Counts[3]; // total level 3 recommendations - level3RecommendationRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level3RecommendationRow.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level3RecommendationRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level3RecommendationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 3 recommendations - let level3HiddenRCounts = 0; - for (const property in level3RrowValues) { - level3HiddenRCounts += level3RrowValues[property][1]; - } - - level3RecommendationRow.getCell(3).value = level3HiddenRCounts; // hidden level 3 recommendations - level3RecommendationRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level3RecommendationRow.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level3RecommendationRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level3RecommendationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 3 Recommendation Rows - - // build rows - rowArray = []; - - for (const property in level3RrowValues) { - let row = [" " + `${property}`, parseInt(`${level3RrowValues[property][0]}`), parseInt(`${level3RrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - - ///////////////////////////// - // build Level 4 title - ///////////////////////////// - - const level4Row = worksheet.addRow(["", 0]); - level4Row.height = 27; // actual is 36 - - level4Row.getCell(1).value = "Level 4 - further recommended improvements to accessibility"; - level4Row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level4Row.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level4Row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - level4Row.getCell(2).value = level4Counts[0]; // total Level 4 issues - level4Row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level4Row.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level4Row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - level4Row.getCell(3).value = level4Counts[4]; // Level 1 hidden counts - level4Row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level4Row.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - level4Row.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - level4Row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 4 Violation title - const level4ViolationRow = worksheet.addRow(["", 0]); - level4ViolationRow.height = 18; // target is 21 - - level4ViolationRow.getCell(1).value = " Violation"; - level4ViolationRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level4ViolationRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level4ViolationRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level4ViolationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level4ViolationRow.getCell(2).value = level4Counts[1]; // total level 4 violations - level4ViolationRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level4ViolationRow.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level4ViolationRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level4ViolationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 4 violations - let level4HiddenVCounts = 0; - for (const property in level4VrowValues) { - level4HiddenVCounts += level4VrowValues[property][1]; - } - - level4ViolationRow.getCell(3).value = level4HiddenVCounts; // total level 4 violations - level4ViolationRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level4ViolationRow.getCell(3).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level4ViolationRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } }; - level4ViolationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 4 Violation Rows - - // build rows - rowArray = []; - - for (const property in level4VrowValues) { - let row = [" " + `${property}`, parseInt(`${level4VrowValues[property][0]}`), parseInt(`${level4VrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - - // Level 4 Needs review title - const level4NeedsReviewRow = worksheet.addRow(["", 0]); - level4NeedsReviewRow.height = 18; // target is 21 - - level4NeedsReviewRow.getCell(1).value = " Needs review"; - level4NeedsReviewRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level4NeedsReviewRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level4NeedsReviewRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level4NeedsReviewRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level4NeedsReviewRow.getCell(2).value = level4Counts[2]; // total level 4 needs review - level4NeedsReviewRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level4NeedsReviewRow.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level4NeedsReviewRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level4NeedsReviewRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 4 needs review - let level4HiddenNRCounts = 0; - for (const property in level4NRrowValues) { - level4HiddenNRCounts += level4NRrowValues[property][1]; - } - - level4NeedsReviewRow.getCell(3).value = level4HiddenNRCounts; // total level 4 needs review - level4NeedsReviewRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level4NeedsReviewRow.getCell(3).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level4NeedsReviewRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } }; - level4NeedsReviewRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 4 Needs review Rows - - // build rows - rowArray = []; - - for (const property in level4NRrowValues) { - let row = [" " + `${property}`, parseInt(`${level4NRrowValues[property][0]}`), parseInt(`${level4NRrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - //row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - //row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); - - // Level 4 Recommendation title - const level4RecommendationRow = worksheet.addRow(["", 0]); - level4RecommendationRow.height = 18; // target is 21 - - level4RecommendationRow.getCell(1).value = " Recommendation"; - level4RecommendationRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - level4RecommendationRow.getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - level4RecommendationRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level4RecommendationRow.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // right: {style:'thin', color: {argb: 'FFA6A6A6'}} - }; - - level4RecommendationRow.getCell(2).value = level4Counts[3]; // total level 4 recommendations - level4RecommendationRow.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - level4RecommendationRow.getCell(2).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level4RecommendationRow.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level4RecommendationRow.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // hidden counts for level 4 recommendations - let level4HiddenRCounts = 0; - for (const property in level4RrowValues) { - level4HiddenRCounts += level4RrowValues[property][1]; - } - - level4RecommendationRow.getCell(3).value = level4HiddenRCounts; // total level 4 recommendations - level4RecommendationRow.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - level4RecommendationRow.getCell(3).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - level4RecommendationRow.getCell(3).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } }; - level4RecommendationRow.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // Level 4 Recommendation Rows - - // build rows - rowArray = []; - - for (const property in level4RrowValues) { - let row = [" " + `${property}`, parseInt(`${level4RrowValues[property][0]}`), parseInt(`${level4RrowValues[property][1]}`) - ]; - rowArray.push(row); - } - - // sort array according to count - rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1); - - // add array of rows - - rows = []; - - rows = worksheet.addRows(rowArray); - - rows.forEach((row: any) => { - row.height = 14; - row.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - row.getCell(2).alignment = { vertical: "middle", horizontal: "right" }; - row.getCell(3).alignment = { vertical: "middle", horizontal: "center" }; - row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - row.getCell(1).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - }; - row.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - row.getCell(3).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - // left: {style:'thin', color: {argb: 'FFA6A6A6'}}, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - }); + // stickyRowsCount freezes the header row while scrolling. + // Row banding and autofilter come from the real Excel table injected in injectTable(). + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; +} +function buildDefinitionsSheet(): any { + const columns = [{ width: 41.51 }, { width: 119.51 }]; + + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHdrStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + + const summaryDefs = [ + { key1: "Page", key2: "Identifies the page or html file that was scanned." }, + { key1: "Scan label", key2: "Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing." }, + { key1: "Base scan", key2: "Scan label for a previous scan against which this scan was compared. Only new issues are reported when a base scan is used." }, + { key1: "Violations", key2: "Accessibility failures that need to be corrected." }, + { key1: "Needs review", key2: "Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem." }, + { key1: "Recommendations", key2: "Opportunities to apply best practices to further improve accessibility." }, + { key1: "Hidden", key2: "Issues the user has selected to be hidden from view and subtracted from the issue counts." }, + { key1: "% elements without violations", key2: "Percentage of elements on the page that had no violations found." }, + { key1: "% elements without violations or items to review", key2: "Percentage of elements on the page that had no violations found and no items to review." }, + { key1: "Level 1,2,3", key2: "Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details." }, + ]; + + const issuesDefs = [ + { key1: "Page", key2: "Identifies the page or html file that was scanned." }, + { key1: "Scan label", key2: "Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing." }, + { key1: "Issue ID", key2: "Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. " }, + { key1: "Issue type", key2: "Violation, needs review, or recommendation" }, + { key1: "Toolkit level", key2: "1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details" }, + { key1: "Checkpoint", key2: "Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into." }, + { key1: "WCAG level", key2: "A, AA or AAA. WCAG level for this issue." }, + { key1: "Rule", key2: "Name of the accessibility test rule that detected this issue." }, + { key1: "Issue", key2: "Message describing the issue." }, + { key1: "Element", key2: "Type of HTML element where the issue is found." }, + { key1: "Code", key2: "Actual HTML element where the issue is found." }, + { key1: "Xpath", key2: "Xpath of the HTML element where the issue is found." }, + { key1: "Help", key2: "Link to a more detailed description of the issue and suggested solutions." }, + ]; + + const data: any[][] = []; + + data.push([{ value: "Definition of fields", ...titleStyle, height: 36, columnSpan: 2 }, null]); + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + data.push([{ value: "Scan summary and Issue summary", ...sectionStyle, height: 20, columnSpan: 2 }, null]); + data.push([{ value: "Field", ...subHdrStyle, height: 16 }, { value: "Definition", ...subHdrStyle }]); + for (const row of summaryDefs) { + data.push([{ value: row.key1, ...dataStyle }, { value: row.key2, ...dataStyle }]); } - - private createIssuesSheet(storedScans: IStoredReportMeta[]) { - const worksheet = this.workbook.addWorksheet("Issues"); - - // build rows - let rowArray = []; - for (const storedScan of storedScans) { - const myStoredData = storedScan.storedScanData; - for (let i = 0; i < myStoredData.length; i++) { - let row = [myStoredData[i][0], myStoredData[i][1], storedScan.label, - myStoredData[i][3], myStoredData[i][14] ? "Hidden:"+myStoredData[i][4] : myStoredData[i][4], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][5], - myStoredData[i][6], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][7], myStoredData[i][8], - myStoredData[i][9], myStoredData[i][10], myStoredData[i][11], - myStoredData[i][12], myStoredData[i][13] - ]; - rowArray.push(row); - } - } - - // column widths - const colWidthData : Array<{ - col: string, - width: number, - alignment: Partial - }> = [ - { col: 'A', width: 18.0, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'B', width: 20.5, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'C', width: 21.0, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'D', width: 18.5, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'E', width: 23.0, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'F', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'G', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'H', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'I', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'J', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'K', width: 14.00, alignment: { vertical: "middle", horizontal: "center" } }, - { col: 'L', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'M', width: 43.00, alignment: { vertical: "middle", horizontal: "left" } }, - { col: 'N', width: 17.17, alignment: { vertical: "middle", horizontal: "fill" } }, - ] - - for (let i = 0; i < 14; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - worksheet.getColumn(colWidthData[i].col).alignment = colWidthData[i].alignment; - } - - // set font and alignment for the header cells - for (let i = 1; i < 15; i++) { - worksheet.getRow(1).getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true }; - worksheet.getRow(1).getCell(i).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 }; - worksheet.getRow(1).getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - worksheet.getRow(1).getCell(i).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } - - // height for header row - worksheet.getRow(1).height = 24; - - // add table to a sheet - worksheet.addTable({ - name: 'MyTable', - ref: 'A1', - headerRow: true, - // totalsRow: true, - style: { - theme: 'TableStyleMedium2', - showRowStripes: true, - }, - columns: [ - { name: 'Page title', filterButton: true }, - { name: 'Page URL', filterButton: true }, - { name: 'Scan label', filterButton: true }, - { name: 'Issue ID', filterButton: true }, - { name: 'Issue type', filterButton: true }, - { name: 'Toolkit level', filterButton: true }, - { name: 'Checkpoint', filterButton: true }, - { name: 'WCAG level', filterButton: true }, - { name: 'Rule', filterButton: true }, - { name: 'Issue', filterButton: true }, - { name: 'Element', filterButton: true }, - { name: 'Code', filterButton: true }, - { name: 'Xpath', filterButton: true }, - { name: 'Help', filterButton: true }, - - ], - rows: rowArray - }); - - for (let i = 2; i <= rowArray.length + 1; i++) { - worksheet.getRow(i).height = 14; - for (let j = 1; j <= 14; j++) { - worksheet.getRow(i).getCell(j).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - } - } - } + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + data.push([{ value: "Issues", ...sectionStyle, height: 20, columnSpan: 2 }, null]); + data.push([{ value: "Field", ...subHdrStyle, height: 16 }, { value: "Definition", ...subHdrStyle }]); + for (const row of issuesDefs) { + data.push([{ value: row.key1, ...dataStyle }, { value: row.key2, ...dataStyle }]); } - private createDefinitionsSheet() { - - const worksheet = this.workbook.addWorksheet("Definition of fields"); - - // "Definition of fields" title - worksheet.mergeCells('A1', "B1"); - - const titleRow = worksheet.getRow(1); - titleRow.height = 36; // actual is 48 - - titleRow.getCell(1).value = "Definition of fields"; - titleRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - titleRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 20 }; - titleRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - const colWidthData = [ - { col: 'A', width: 41.51 }, // note .84 added to actual width - { col: 'B', width: 119.51 }, - ] - - for (let i = 0; i < 2; i++) { - worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width; - } - - // blank row - worksheet.mergeCells('A2', "B2"); - const blankRow = worksheet.getRow(2); - blankRow.height = 12; // actual is 16 - - // "Scan summary and Issue summary" title - worksheet.mergeCells('A3', "B3"); - - const summaryRow = worksheet.getRow(3); - summaryRow.height = 20; // actual is 26.75 - - summaryRow.getCell(1).value = "Scan summary and Issue summary"; - summaryRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - summaryRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - summaryRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - // row 4 Field / Definition - const row4 = worksheet.getRow(4); - row4.height = 16; // actual is - - row4.getCell(1).value = "Field"; - row4.getCell(2).value = "Definition"; - row4.getCell(1).alignment = row4.getCell(2).alignment = { vertical: "middle", horizontal: "left" }; - row4.getCell(1).font = row4.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 }; - row4.getCell(1).fill = row4.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } }; - row4.getCell(1).border = row4.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; - - // rows 5-13 - - // set row height for rows 5-13 - for (let i = 5; i < 14; i++) { - worksheet.getRow(i).height = 12; // results in a row height of 16 - } - - let rowData = [ - { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, - { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, - { key1: 'Base scan', key2: 'Scan label for a previous scan against which this scan was compared. Only new issues are reported when a base scan is used.' }, - { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, - { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, - { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, - { key1: 'Hidden', key2: 'Issues the user has selected to be hidden from view and subtracted from the issue counts.' }, - { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, - { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, - { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } - ]; - - for (let i = 5; i < 14; i++) { - worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" }; - - } - for (let i = 5; i < 14; i++) { - worksheet.getRow(i).getCell(1).value = rowData[i - 5].key1; worksheet.getRow(i).getCell(2).value = rowData[i - 5].key2; - } + return { data, sheet: "Definition of fields", columns }; +} - // "Scan summary and Issue summary" title - worksheet.mergeCells('A14', "B14"); - - const issuesRow = worksheet.getRow(14); - issuesRow.height = 20; // actual is 26.75 - - issuesRow.getCell(1).value = "Issues"; - issuesRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" }; - issuesRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 }; - issuesRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } }; - - // row 15 Field / Definition - const row15 = worksheet.getRow(15); - row15.height = 16; // actual is - - row15.getCell(1).value = "Field"; - row15.getCell(2).value = "Definition"; - row15.getCell(1).alignment = row15.getCell(2).alignment = { vertical: "middle", horizontal: "left" }; - row15.getCell(1).font = row15.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 }; - row15.getCell(1).fill = row15.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } }; - row15.getCell(1).border = row15.getCell(2).border = { - top: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - left: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } }, - right: { style: 'thin', color: { argb: 'FFA6A6A6' } } - }; +// ─── Public API ──────────────────────────────────────────────────────────────── - // rows 16-28 +export default class MultiScanReport { - // set row height for rows 16-28 - for (let i = 16; i < 29; i++) { - worksheet.getRow(i).height = 12; // results in a row height of 16 - } + public static async multiScanXlsxDownload(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]) { + const blob = await MultiScanReport.generateBlob(storedScans, archives); + const fileName = ReportUtil.single_page_report_file_name(storedScans[storedScans.length - 1].pageTitle); + ReportUtil.download_file(blob, fileName); + } - rowData = []; - - rowData = [ - { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, - { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, - { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, - { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, - { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, - { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, - { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, - { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, - { key1: 'Issue', key2: 'Message describing the issue.' }, - { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, - { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, - { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, - { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + public static async generateBlob(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]): Promise { + const issuesSheet = buildIssuesSheet(storedScans); + const issueRowCount: number = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + + const sheets = [ + buildOverviewSheet(storedScans, archives), + buildScanSummarySheet(storedScans), + buildIssueSummarySheet(storedScans), + issuesSheet, + buildDefinitionsSheet(), ]; - - for (let i = 16; i < 29; i++) { - worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 }; - worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" }; - - } - for (let i = 16; i < 29; i++) { - worksheet.getRow(i).getCell(1).value = rowData[i - 16].key1; worksheet.getRow(i).getCell(2).value = rowData[i - 16].key2; - } - + const blob = await writeExcelFile(sheets).toBlob(); + return injectTable(blob, issueRowCount); } - private static countDuplicatesInArray(array: {issueDef: string; hidden: boolean;}[]) { // count issues with duplicate description string - let dupCount : { - [key: string]: number - } = {}; - let hidCount : { - [key: string]: number - } = {}; - let finalCount: { - [key: string]: [number,number] - } = {}; - for (const item of array) { - if (!item.hidden) { - dupCount[item.issueDef] = (dupCount[item.issueDef] || 0) + 1; - hidCount[item.issueDef] = (hidCount[item.issueDef] || 0) + 0; - } else { - dupCount[item.issueDef] = (dupCount[item.issueDef] || 0) + 0; - hidCount[item.issueDef] = (hidCount[item.issueDef] || 0) + 1; + /** @deprecated Use generateBlob() instead */ + public static async generateWorkbook(storedScans: IStoredReportMeta[], archives: IArchiveDefinition[]) { + // Returns a pseudo-workbook whose only capability is xlsx.writeBuffer(), + // preserved for any callers that may still call this method. + return { + xlsx: { + writeBuffer: async () => { + const blob = await MultiScanReport.generateBlob(storedScans, archives); + return await blob.arrayBuffer(); + } } - finalCount[item.issueDef] = [dupCount[item.issueDef], hidCount[item.issueDef]] - } - return finalCount; - } -} \ No newline at end of file + }; + } +} diff --git a/accessibility-checker-extension/test/package-lock.json b/accessibility-checker-extension/test/package-lock.json index 95d294279..01276f12c 100644 --- a/accessibility-checker-extension/test/package-lock.json +++ b/accessibility-checker-extension/test/package-lock.json @@ -1691,9 +1691,9 @@ } }, "node_modules/ip-address": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", - "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", + "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", "dev": true, "license": "MIT", "engines": { diff --git a/accessibility-checker/package.json b/accessibility-checker/package.json index ab855803c..d01e30153 100644 --- a/accessibility-checker/package.json +++ b/accessibility-checker/package.json @@ -31,6 +31,7 @@ } }, "dependencies": { + "adm-zip": "^0.5.9", "chromedriver": "*", "microdiff": "^1.5.0", "js-yaml": "^4.2.0", @@ -40,7 +41,6 @@ "@ibm/telemetry-js": "^1.9.1", "@playwright/test": "^1.21.1", "@types/node": "^20.17.24", - "adm-zip": "^0.5.9", "chai": "^4.3.4", "eslint": "^8.4.1", "express": "^4.17.1", diff --git a/accessibility-checker/src/README.md b/accessibility-checker/src/README.md index c0902c1ab..3d03cf972 100644 --- a/accessibility-checker/src/README.md +++ b/accessibility-checker/src/README.md @@ -119,6 +119,16 @@ $ npm install -g accessibility-checker $ achecker ``` +## Optional: XLSX Report Format + +If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: + +```bash +$ npm install --save-dev write-excel-file adm-zip +``` + +Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. + ## Setup 1. Setup and Initialize - Follow the [Prerequisites](#prerequisites) and [Install](#install) instructions. diff --git a/common/module/package-lock.json b/common/module/package-lock.json index 7e302aa83..d91205868 100644 --- a/common/module/package-lock.json +++ b/common/module/package-lock.json @@ -24,9 +24,13 @@ "node": ">=16" }, "peerDependencies": { + "adm-zip": "^0.5.9", "write-excel-file": "^4.1.1" }, "peerDependenciesMeta": { + "adm-zip": { + "optional": true + }, "write-excel-file": { "optional": true } @@ -1702,9 +1706,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.416", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", - "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", + "version": "1.5.417", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz", + "integrity": "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ==", "dev": true, "license": "ISC" }, diff --git a/common/module/package.json b/common/module/package.json index 3a8adbdb7..2c74f20f7 100644 --- a/common/module/package.json +++ b/common/module/package.json @@ -23,11 +23,15 @@ "typescript": "^5.1.3" }, "peerDependencies": { - "write-excel-file": "^4.1.1" + "write-excel-file": "^4.1.1", + "adm-zip": "^0.5.9" }, "peerDependenciesMeta": { "write-excel-file": { "optional": true + }, + "adm-zip": { + "optional": true } }, "dependencies": { diff --git a/common/module/src/report/ACReporterXLSX.ts b/common/module/src/report/ACReporterXLSX.ts index 45ceaadfa..888040ba0 100644 --- a/common/module/src/report/ACReporterXLSX.ts +++ b/common/module/src/report/ACReporterXLSX.ts @@ -19,7 +19,6 @@ import { Checkpoint, Guideline, eToolkitLevel } from "../engine/IGuideline.js"; import { CompressedReport } from "../engine/IReport.js"; import { eRuleConfidence } from "../engine/IRule.js"; import { GenSummReturn, IReporter, ReporterManager } from "./ReporterManager.js"; - // Lazy-load write-excel-file — will be null if not installed let writeExcelLoadPromise: Promise | null = null; let writeExcelWarningShown = false; @@ -71,7 +70,7 @@ function headerCell(value: string | number, columnSpan?: number): any { const cell: any = { value, backgroundColor: "#403151", - color: "#FFFFFF", + textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", @@ -88,7 +87,7 @@ function dataCell(value: string | number | null, opts?: any): any { value, fontFamily: "Calibri", fontSize: 12, - color: "#000000", + textColor: "#000000", ...opts }; } @@ -99,13 +98,120 @@ function borderedCell(value: string | number | null, opts?: any): any { value, fontFamily: "Calibri", fontSize: 12, - color: "#000000", + textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", ...opts }; } +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. + +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title","Page URL","Scan label","Issue ID","Issue type", + "Toolkit level","Checkpoint","WCAG level","Rule","Issue", + "Element","Code","Xpath","Help", +]; + +function buildTableXml(rowCount: number): string { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => + `` + ).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} + +function unzipFile(filePath: string): { [name: string]: Buffer } { + const AdmZip = require("adm-zip"); + const zip = new AdmZip(filePath); + const entries: { [name: string]: Buffer } = {}; + for (const entry of zip.getEntries()) { + entries[entry.entryName] = entry.getData(); + } + return entries; +} + +async function injectTableIntoFile(filePath: string, issueRowCount: number): Promise { + // We use adm-zip (a common Node XLSX-ecosystem dep) if available, + // otherwise fall back to the JSZip that write-excel-file itself bundles. + let AdmZip: any; + try { + AdmZip = require("adm-zip"); + } catch { + // adm-zip not available — skip table injection gracefully + return; + } + + const zip = new AdmZip(filePath); + + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from( + existing.replace("", tableRel + ""), + "utf8" + )); + } else { + zip.addFile(relsPath, Buffer.from( + `` + + `` + + tableRel + ``, + "utf8" + )); + } + + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from( + sheetXml.replace( + "", + `` + ), + "utf8" + )); + + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from( + ctXml.replace( + "", + `` + ), + "utf8" + )); + + zip.writeZip(filePath); +} + export class ACReporterXLSX implements IReporter { public name(): string { return "xlsx"; @@ -150,14 +256,19 @@ export class ACReporterXLSX implements IReporter { showWriteExcelWarning(); return; } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount: number = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ ACReporterXLSX.createOverviewSheet(config, summaryData), ACReporterXLSX.createScanSummarySheet(config, summaryData), ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), - ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData), + issuesSheet, ACReporterXLSX.createDefinitionsSheet(), ]; await writeExcelFile(sheets).toFile(filename); + await injectTableIntoFile(filename, issueRowCount); } } } @@ -202,7 +313,7 @@ export class ACReporterXLSX implements IReporter { // Row 1: Title spanning 5 cols data.push([ - { value: "Accessibility Scan Report", backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, null, null, null, null ]); @@ -210,7 +321,7 @@ export class ACReporterXLSX implements IReporter { for (const row of rowData) { data.push([ dataCell(row.key1, { align: "left", height: 12 }), - { value: row.key2, fontFamily: "Calibri", fontSize: 12, color: "#000000", align: "left", columnSpan: 4 }, + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, null, null, null ]); } @@ -226,17 +337,17 @@ export class ACReporterXLSX implements IReporter { // Row 11: "Summary" title spanning 5 cols data.push([ - { value: "Summary", backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, null, null, null, null ]); // Row 12: column headers data.push([ - borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", color: "#FFFFFF", height: 16 }), - borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", color: "#000000" }), - borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", color: "#000000" }), - borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", color: "#000000" }), - borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", color: "#000000" }), + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), ]); // Row 13: values @@ -264,7 +375,7 @@ export class ACReporterXLSX implements IReporter { { width: 17.17 }, ]; - const headerStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; const countHeaderStyle = { ...headerStyle, align: "center", wrap: true }; const data: any[][] = []; @@ -274,10 +385,10 @@ export class ACReporterXLSX implements IReporter { { value: "Page title", ...headerStyle, align: "left" }, { value: "Page url", ...headerStyle, align: "left" }, { value: "Scan label", ...headerStyle, align: "left" }, - { value: "Violations", ...countHeaderStyle, backgroundColor: "#E4AAAF", color: "#000000" }, - { value: "Needs review", ...countHeaderStyle, backgroundColor: "#F4E08A", color: "#000000" }, - { value: "Recommendations", ...countHeaderStyle, backgroundColor: "#96A9D7", color: "#000000" }, - { value: "Archived", ...countHeaderStyle, backgroundColor: "#FFFFFF", color: "#000000" }, + { value: "Violations", ...countHeaderStyle, backgroundColor: "#E4AAAF", textColor: "#000000" }, + { value: "Needs review", ...countHeaderStyle, backgroundColor: "#F4E08A", textColor: "#000000" }, + { value: "Recommendations", ...countHeaderStyle, backgroundColor: "#96A9D7", textColor: "#000000" }, + { value: "Archived", ...countHeaderStyle, backgroundColor: "#FFFFFF", textColor: "#000000" }, { value: "% elements without violations", ...countHeaderStyle }, { value: "% elements without violations or items to review", ...countHeaderStyle }, ]); @@ -285,7 +396,7 @@ export class ACReporterXLSX implements IReporter { for (const compressedScan of compressedScans) { let storedScan = ReporterManager.uncompressReport(compressedScan); let counts = storedScan.engineReport.summary.counts; - const textStyle = { fontFamily: "Calibri", fontSize: 12, color: "#000000", alignVertical: "center", height: 37, wrap: true }; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; const numStyle = { ...textStyle, align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }; data.push([ { value: storedScan.pageTitle, ...textStyle, align: "left" }, @@ -308,8 +419,8 @@ export class ACReporterXLSX implements IReporter { // Level type title row (e.g. "Violations") rows.push([ - { value: ` ${title}`, backgroundColor: fillColor, color: textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, - { value: levelCount, backgroundColor: fillColor, color: textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, ]); // Individual issue message rows, sorted descending by count @@ -321,8 +432,8 @@ export class ACReporterXLSX implements IReporter { for (const [msg, count] of rowArray) { rows.push([ - { value: msg, fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, - { value: count, fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, ]); } @@ -334,8 +445,8 @@ export class ACReporterXLSX implements IReporter { // Level title row (e.g. "Level 1 - the most essential...") rows.push([ - { value: title, backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, - { value: levelCounts[0], backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, ]); rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); @@ -451,26 +562,26 @@ export class ACReporterXLSX implements IReporter { // Row 1: "Issue summary" title spanning 2 cols data.push([ - { value: "Issue summary", backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, null ]); // Row 2: description spanning 2 cols data.push([ - { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, color: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, null ]); // Row 3: "Total issues found:" with value data.push([ - { value: "Total issues found:", backgroundColor: "#000000", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, - { value: totalIssues, backgroundColor: "#000000", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, ]); // Row 4: "Number of issues" label data.push([ { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, - { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, ]); data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); @@ -520,7 +631,9 @@ export class ACReporterXLSX implements IReporter { { width: 17.17 }, ]; - const hStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", align: "center", alignVertical: "center", wrap: true, height: 24 }; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; const data: any[][] = []; @@ -558,7 +671,7 @@ export class ACReporterXLSX implements IReporter { let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); cpStrs.sort(); - const dStyle = { fontFamily: "Calibri", fontSize: 12, color: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", height: 14 }; + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; data.push([ { value: storedScan.pageTitle, ...dStyle, align: "left", alignVertical: "center" }, { value: storedScan.engineReport.summary.URL, ...dStyle, align: "left", alignVertical: "center" }, @@ -578,7 +691,7 @@ export class ACReporterXLSX implements IReporter { } } - return { data, sheet: "Issues", columns }; + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; } private static createDefinitionsSheet(): any { @@ -587,10 +700,10 @@ export class ACReporterXLSX implements IReporter { { width: 119.51 }, ]; - const titleStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; - const sectionStyle = { backgroundColor: "#403151", color: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; - const subHeaderStyle = { backgroundColor: "#CCC0DA", color: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; - const dataStyle = { fontFamily: "Calibri", fontSize: 12, color: "#000000", align: "left", height: 12 }; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; const summaryRowData = [ { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, diff --git a/cypress-accessibility-checker/README.md b/cypress-accessibility-checker/README.md index 39688ee1e..8ead43210 100644 --- a/cypress-accessibility-checker/README.md +++ b/cypress-accessibility-checker/README.md @@ -31,13 +31,13 @@ npm install cypress-accessibility-checker --save-dev ### Optional: XLSX Report Format -If you want to generate reports in XLSX format, you need to install `exceljs` as an additional dependency: +If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: ```bash -npm install exceljs --save-dev +npm install write-excel-file adm-zip --save-dev ``` -Without `exceljs` installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. +Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. ## Configuration diff --git a/cypress-accessibility-checker/boilerplates/package-lock.json b/cypress-accessibility-checker/boilerplates/package-lock.json index 7381a761b..67ba2f6ff 100644 --- a/cypress-accessibility-checker/boilerplates/package-lock.json +++ b/cypress-accessibility-checker/boilerplates/package-lock.json @@ -3065,9 +3065,9 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3601,9 +3601,9 @@ } }, "node_modules/systeminformation": { - "version": "5.33.5", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.5.tgz", - "integrity": "sha512-0v8l1CwFOAjfkv6ynpMrv3YGjH0M7PWCpZwusr8J1TEoQFPK7WXO6gbeAiandaWoh7vbMdnFtDqVotJVnLJtIg==", + "version": "5.33.6", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.6.tgz", + "integrity": "sha512-hMOQG/eRUzuopuYGGdl8ntkau0nEC7fOaRoTUg1RSr2GTQIk2VNa76DA0+ApajkGfzmcgAupgIP/vt+jtoe5EA==", "dev": true, "license": "MIT", "os": [ diff --git a/cypress-accessibility-checker/package-lock.json b/cypress-accessibility-checker/package-lock.json index ea9f95cee..7cf6367c2 100644 --- a/cypress-accessibility-checker/package-lock.json +++ b/cypress-accessibility-checker/package-lock.json @@ -1485,9 +1485,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", - "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", "dev": true, "license": "ISC", "dependencies": { @@ -2960,9 +2960,9 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3591,9 +3591,9 @@ } }, "node_modules/systeminformation": { - "version": "5.33.5", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.5.tgz", - "integrity": "sha512-0v8l1CwFOAjfkv6ynpMrv3YGjH0M7PWCpZwusr8J1TEoQFPK7WXO6gbeAiandaWoh7vbMdnFtDqVotJVnLJtIg==", + "version": "5.33.6", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.6.tgz", + "integrity": "sha512-hMOQG/eRUzuopuYGGdl8ntkau0nEC7fOaRoTUg1RSr2GTQIk2VNa76DA0+ApajkGfzmcgAupgIP/vt+jtoe5EA==", "dev": true, "license": "MIT", "os": [ diff --git a/karma-accessibility-checker/README.md b/karma-accessibility-checker/README.md index 5b0d948e5..f72309c12 100644 --- a/karma-accessibility-checker/README.md +++ b/karma-accessibility-checker/README.md @@ -32,13 +32,13 @@ All bugs or issues related to the karma-accessibility-checker code can be create ## Optional: XLSX Report Format -If you want to generate reports in XLSX format, you need to install `exceljs` as an additional dependency: +If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: ```bash -$ npm install exceljs +$ npm install write-excel-file adm-zip ``` -Without `exceljs` installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. +Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. ## Running Locally diff --git a/report-react/package-lock.json b/report-react/package-lock.json index c26e6c608..f7d1c26af 100644 --- a/report-react/package-lock.json +++ b/report-react/package-lock.json @@ -5977,6 +5977,22 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/bonjour-service": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.4.tgz", @@ -7731,9 +7747,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.416", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", - "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", + "version": "1.5.417", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz", + "integrity": "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ==", "license": "ISC" }, "node_modules/emittery": { @@ -8897,6 +8913,22 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/express/node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -8993,9 +9025,9 @@ } }, "node_modules/fastq": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", - "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -13247,9 +13279,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.25", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.25.tgz", - "integrity": "sha512-kktSgNDIbyEIs/LrE6dtEMnfzxSDpXViFl6c4gFjz/CgtnL4GDCR3wyZXzjvAXsNB8dXU4dAfvIOgLMH2/vwLg==", + "version": "2.2.27", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.27.tgz", + "integrity": "sha512-gQPNF78qebCQ6tvVFBYrvJdBNOrYZm90ZlXgpIFm06p6qHDHq/XC4TnJftN6OMbxVE0UTBAoRgcsDeJBBooITw==", "license": "MIT" }, "node_modules/object-assign": { @@ -15307,9 +15339,10 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "es-define-property": "^1.0.1", @@ -17285,24 +17318,24 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.1.0.tgz", + "integrity": "sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", + "es-abstract": "^1.24.2", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", + "es-object-atoms": "^1.1.2", + "get-intrinsic": "^1.3.0", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", + "regexp.prototype.flags": "^1.5.4", "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" + "side-channel": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -19056,9 +19089,9 @@ } }, "node_modules/webpack": { - "version": "5.110.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.1.tgz", - "integrity": "sha512-gInQB+jxXxgnZyvPwuzT5NGQmECDqeu85oxcrjinrYHqPoBex0hCAN2SFTJVyPVrK0Pq9E44VFP+e89fAc10/w==", + "version": "5.110.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.2.tgz", + "integrity": "sha512-TciLrfM7zgEjqGdY851HkirDsSPQgTFsWQpl9oHqMAMYsHhEC0bKjscvjpnz+pzx10hLC8qISApGrsnrCP4UtQ==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", diff --git a/rule-server/package-lock.json b/rule-server/package-lock.json index db3a9429e..2a61233b6 100644 --- a/rule-server/package-lock.json +++ b/rule-server/package-lock.json @@ -2451,9 +2451,9 @@ } }, "node_modules/fastq": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", - "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", "dev": true, "license": "ISC", "dependencies": { diff --git a/vitest-accessibility-checker/README.md b/vitest-accessibility-checker/README.md index 2ea56cf87..703840869 100644 --- a/vitest-accessibility-checker/README.md +++ b/vitest-accessibility-checker/README.md @@ -108,6 +108,16 @@ $ npm install $ npm run test:browser ``` +## Optional: XLSX Report Format + +If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: + +```bash +$ npm install --save-dev write-excel-file adm-zip +``` + +Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. + ## Known issues and workarounds 1. **Browser not found error**: If you see "Executable doesn't exist" errors, install Playwright browsers: diff --git a/vitest-accessibility-checker/package-lock.json b/vitest-accessibility-checker/package-lock.json index a7316fa7d..7c4017d63 100644 --- a/vitest-accessibility-checker/package-lock.json +++ b/vitest-accessibility-checker/package-lock.json @@ -1322,9 +1322,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", - "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", "dev": true, "license": "ISC", "dependencies": { @@ -2625,9 +2625,9 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { From 5c5e2cb6d37814473e1d687123af8a66a5673b22 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 11:48:50 -0500 Subject: [PATCH 04/12] Fix cypress error --- common/module/src/report/ACReporterXLSX.ts | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/common/module/src/report/ACReporterXLSX.ts b/common/module/src/report/ACReporterXLSX.ts index 888040ba0..a4baaf886 100644 --- a/common/module/src/report/ACReporterXLSX.ts +++ b/common/module/src/report/ACReporterXLSX.ts @@ -138,22 +138,12 @@ function buildTableXml(rowCount: number): string { ``; } -function unzipFile(filePath: string): { [name: string]: Buffer } { - const AdmZip = require("adm-zip"); - const zip = new AdmZip(filePath); - const entries: { [name: string]: Buffer } = {}; - for (const entry of zip.getEntries()) { - entries[entry.entryName] = entry.getData(); - } - return entries; -} - async function injectTableIntoFile(filePath: string, issueRowCount: number): Promise { - // We use adm-zip (a common Node XLSX-ecosystem dep) if available, - // otherwise fall back to the JSZip that write-excel-file itself bundles. let AdmZip: any; try { - AdmZip = require("adm-zip"); + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); } catch { // adm-zip not available — skip table injection gracefully return; From 32f61c1c0b8c8f074eac330516734fc379e8f188 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 11:55:15 -0500 Subject: [PATCH 05/12] fix test --- .../test/support/steps/steps_excel.ts | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/accessibility-checker-extension/test/support/steps/steps_excel.ts b/accessibility-checker-extension/test/support/steps/steps_excel.ts index 8707822fe..2bdc9a310 100644 --- a/accessibility-checker-extension/test/support/steps/steps_excel.ts +++ b/accessibility-checker-extension/test/support/steps/steps_excel.ts @@ -6,23 +6,21 @@ import { strict as assert } from "assert"; Given("excel file {string}", async function(filename: string) { const filePath = join(PupUtil.getTempDownloadFolder(), filename); - const sheets = await readExcelFile(filePath); - this.excelFile = sheets; + // readExcelFile default export returns Sheet[] — each element is { sheet: string, data: Row[] } + this.excelFile = await readExcelFile(filePath); }); -Then ("Excel Sheet {string} Cell {string} is {string}", async function(sheetStr: string, cellStr: string, txt: string) { - // read-excel-file returns sheets as an array; we need to find by sheet name - // re-read to get named sheets - const filePath = join(PupUtil.getTempDownloadFolder(), this.excelFileName); - const allSheets = await readExcelFile(filePath); - // Find the sheet with matching name — readExcelFile returns array of { sheet, data } - const sheetObj = allSheets.find((s: any) => s.sheet === sheetStr); +Then("Excel Sheet {string} Cell {string} is {string}", async function(sheetStr: string, cellStr: string, txt: string) { + assert.ok(this.excelFile, 'No excel file loaded — use the "excel file" step first'); + + const sheetObj = (this.excelFile as any[]).find((s: any) => s.sheet === sheetStr); if (!sheetObj) { - assert.fail(`Sheet "${sheetStr}" does not exist`); + assert.fail(`Sheet "${sheetStr}" does not exist in the workbook`); } - // Parse cell reference like "A1", "B3", etc. - const col = cellStr.charCodeAt(0) - 65; // 'A' = 0 - const row = parseInt(cellStr.slice(1)) - 1; + + // Parse cell reference like "A1", "B12", etc. + const col = cellStr.charCodeAt(0) - 65; // 'A' → 0 + const row = parseInt(cellStr.slice(1)) - 1; // 1-based → 0-based const cellValue = sheetObj.data[row]?.[col]; const cellText = cellValue != null ? String(cellValue) : ""; assert.strictEqual(cellText, txt); From e0a39a1d8e4fcb84406bb86045543593856f359b Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 12:43:02 -0500 Subject: [PATCH 06/12] test(xlsx): add XLSX reporter tests for mocha, vitest/node, and cypress - accessibility-checker: mocha test calling ACReporterXLSX.generateSummary() directly (no rule server needed); validates all 5 sheets and key cells - vitest-accessibility-checker: parallel Node forks test using same approach; vitest.node.config.mjs replaces the .js version (poolOptions removed for v4) - cypress-accessibility-checker: Cypress e2e test + adm-zip tasks in cypress.config.js; adds outputFilenameTimestamp: false to .achecker.yml Fix XLSX XML parser helpers in all three tests: - Sheet name lookup: extract r:id and name attrs independently (write-excel-file emits r:id before name, opposite of the old regex assumption) - Cell parsing: use attribute-order-independent regex that handles both self-closing and full ... forms; index rows by actual Excel row number (sparse array) so merged/skipped rows don't shift indices CI (test.yml): add mocha XLSX + vitest test:node steps to both Linux and Windows basic jobs; add npm install write-excel-file before each step --- .github/workflows/test.yml | 14 +- accessibility-checker/package.json | 2 +- .../aChecker.Scans/aChecker.XLSX.test.mjs | 228 ++++++++++++++++++ .../package-lock.json | 33 ++- cypress-accessibility-checker/package.json | 19 +- .../test/.achecker.yml | 3 + .../test/cypress.config.js | 86 ++++++- .../test/cypress/e2e/achecker-xlsx.cy.js | 86 +++++++ .../package-lock.json | 27 ++- vitest-accessibility-checker/package.json | 4 +- .../test/src/achecker-xlsx.test.js | 190 +++++++++++++++ .../test/vitest.node.config.mjs | 18 ++ 12 files changed, 691 insertions(+), 19 deletions(-) create mode 100644 accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs create mode 100644 cypress-accessibility-checker/test/cypress/e2e/achecker-xlsx.cy.js create mode 100644 vitest-accessibility-checker/test/src/achecker-xlsx.test.js create mode 100644 vitest-accessibility-checker/test/vitest.node.config.mjs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4110def35..653ac7e78 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -145,7 +145,11 @@ jobs: working-directory: accessibility-checker - run: npx mocha -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.mjs working-directory: accessibility-checker - + - run: npm install write-excel-file + working-directory: accessibility-checker + - run: npx mocha --timeout 30000 -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs + working-directory: accessibility-checker + ############################################################################### # Node basic test #### @@ -195,6 +199,10 @@ jobs: working-directory: accessibility-checker - run: npx mocha -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.mjs working-directory: accessibility-checker + - run: npm install write-excel-file + working-directory: accessibility-checker + - run: npx mocha --timeout 30000 -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs + working-directory: accessibility-checker ############################################################################### # Node basic test @@ -551,10 +559,14 @@ jobs: working-directory: vitest-accessibility-checker - run: npx playwright install chromium working-directory: vitest-accessibility-checker + - run: npm install write-excel-file + working-directory: vitest-accessibility-checker - run: npm run build:common working-directory: vitest-accessibility-checker - run: npx vitest run working-directory: vitest-accessibility-checker/test + - run: npm run test:node + working-directory: vitest-accessibility-checker ############################################################################### # Extension Build verification and test diff --git a/accessibility-checker/package.json b/accessibility-checker/package.json index d01e30153..f785d75a1 100644 --- a/accessibility-checker/package.json +++ b/accessibility-checker/package.json @@ -33,8 +33,8 @@ "dependencies": { "adm-zip": "^0.5.9", "chromedriver": "*", - "microdiff": "^1.5.0", "js-yaml": "^4.2.0", + "microdiff": "^1.5.0", "puppeteer": "^25.1.0" }, "devDependencies": { diff --git a/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs new file mode 100644 index 000000000..e55d3d227 --- /dev/null +++ b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs @@ -0,0 +1,228 @@ +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +'use strict'; + +import * as fs from "fs"; +import * as path from "path"; +import * as os from "os"; +import { ACReporterXLSX } from "../../../../src/mjs/lib/common/report/ACReporterXLSX.js"; +import { expect } from "chai"; +import AdmZip from "adm-zip"; + +// --------------------------------------------------------------------------- +// Helpers — parse XLSX (which is a ZIP) to extract sheet data +// --------------------------------------------------------------------------- + +/** + * Returns a map of sheetName → 2-D array of cell values (strings) + * by reading the raw XML inside the XLSX zip. + */ +function readXlsxSheets(filePath) { + const zip = new AdmZip(filePath); + + // Read workbook.xml to get sheet name → rId mapping. + // write-excel-file emits r:id before name, so we extract each attribute + // independently rather than relying on a fixed order. + const wbXml = zip.getEntry("xl/workbook.xml").getData().toString("utf8"); + const sheetNames = []; + const sheetRe = /)/g; + let m; + while ((m = sheetRe.exec(wbXml)) !== null) { + const attrs = m[1]; + const nameM = /name="([^"]+)"/.exec(attrs); + const ridM = /r:id="([^"]+)"/.exec(attrs); + if (nameM && ridM) sheetNames.push({ name: nameM[1], rId: ridM[1] }); + } + + // Read workbook.xml.rels to map rId → sheet file + const relsXml = zip.getEntry("xl/_rels/workbook.xml.rels").getData().toString("utf8"); + const relMap = {}; + const relRe = /]+Id="([^"]+)"[^>]+Target="([^"]+)"/g; + while ((m = relRe.exec(relsXml)) !== null) { + relMap[m[1]] = m[2]; + } + + // Read sharedStrings.xml + const ssEntry = zip.getEntry("xl/sharedStrings.xml"); + const sharedStrings = []; + if (ssEntry) { + const ssXml = ssEntry.getData().toString("utf8"); + const siRe = /([\s\S]*?)<\/si>/g; + while ((m = siRe.exec(ssXml)) !== null) { + // Collect all text nodes within the + const tRe = /]*>([^<]*)<\/t>/g; + let text = ""; + let tm; + while ((tm = tRe.exec(m[1])) !== null) { + text += tm[1]; + } + sharedStrings.push(text); + } + } + + // Parse each sheet's XML into a 2-D array + const result = {}; + for (const { name, rId } of sheetNames) { + const target = relMap[rId]; // e.g. "worksheets/sheet1.xml" + const sheetEntry = zip.getEntry(`xl/${target}`); + if (!sheetEntry) continue; + const sheetXml = sheetEntry.getData().toString("utf8"); + + // Use a sparse array indexed by actual Excel row number (1-based → 0-based index). + // Rows can be sparse (e.g. rows 8–10 omitted when cells use merged spans). + // The regex handles both self-closing () and content (...) forms. + const rows = []; + const cellRe = /|>([\s\S]*?)<\/c>)/g; + let cm; + while ((cm = cellRe.exec(sheetXml)) !== null) { + const colStr = cm[1]; + const rowNum = parseInt(cm[2]) - 1; // 0-based + const attrs = cm[3]; + const inner = cm[4] ?? ""; // undefined for self-closing tags + // Column index (A=0, B=1, …) + let col = 0; + for (const ch of colStr) col = col * 26 + (ch.charCodeAt(0) - 64); + col -= 1; + + if (!rows[rowNum]) rows[rowNum] = []; + const vMatch = /([^<]*)<\/v>/.exec(inner); + if (vMatch) { + if (/t="s"/.test(attrs)) { + rows[rowNum][col] = sharedStrings[parseInt(vMatch[1])] ?? ""; + } else if (/t="inlineStr"/.test(attrs)) { + const tMatch = /([^<]*)<\/t>/.exec(inner); + rows[rowNum][col] = tMatch ? tMatch[1] : ""; + } else { + rows[rowNum][col] = vMatch[1]; + } + } + } + result[name] = rows; + } + return result; +} + +/** Return the value at a cell reference like "A1", "B12" (1-based). */ +function cell(sheets, sheetName, ref) { + const col = ref.charCodeAt(0) - 65; + const row = parseInt(ref.slice(1)) - 1; + return (sheets[sheetName]?.[row]?.[col]) ?? ""; +} + +// --------------------------------------------------------------------------- +// Minimal stub data — compressed array format expected by uncompressReport() +// Indices: [startScan, url, pageTitle, label, scanProfile, numExecuted, +// scanTime, ruleArchive, policies, reportLevels, issues[], counts] +// --------------------------------------------------------------------------- +function makeCompressedReport() { + return [ + Date.now(), // 0 startScan + "http://localhost/test.html", // 1 url + "XLSX mocha test page", // 2 pageTitle + "mocha-xlsx-test", // 3 label + "", // 4 scanProfile + 0, // 5 numExecuted + 0, // 6 scanTime + "Latest", // 7 ruleArchive + ["IBM_Accessibility"], // 8 policies + ["violation","potentialviolation","recommendation","potentialrecommendation","manual"], // 9 reportLevels + [], // 10 issues (compressed results) + { violation: 0, potentialviolation: 0, manual: 0, recommendation: 0, potentialrecommendation: 0, ignored: 0 }, // 11 counts + ]; +} + +// --------------------------------------------------------------------------- +// Test suite +// --------------------------------------------------------------------------- + +describe("XLSX report generation", function () { + this.timeout(30000); + + let xlsxPath; + let sheets; + let outputFolder; + + before(async function () { + outputFolder = fs.mkdtempSync(path.join(os.tmpdir(), "achecker-xlsx-")); + + const config = { + toolID: "4.0.0-test", + ruleArchiveLabel: "Latest Deployment", + policies: ["IBM_Accessibility"], + outputFolder, + outputFilenameTimestamp: false, + }; + + const reporter = new ACReporterXLSX(); + const { summary } = await reporter.generateSummary(config, [], Date.now(), [makeCompressedReport()]); + + xlsxPath = path.join(outputFolder, "results.xlsx"); + await summary(xlsxPath); + + expect(fs.existsSync(xlsxPath), `XLSX file not found at ${xlsxPath}`).to.be.true; + sheets = readXlsxSheets(xlsxPath); + }); + + after(function () { + fs.rmSync(outputFolder, { recursive: true, force: true }); + }); + + it("XLSX file contains the expected sheet names", function () { + expect(Object.keys(sheets)).to.include.members([ + "Overview", + "Scan summary", + "Issue summary", + "Issues", + "Definition of fields", + ]); + }); + + it("Overview sheet A1 is 'Accessibility Scan Report'", function () { + expect(cell(sheets, "Overview", "A1")).to.equal("Accessibility Scan Report"); + }); + + it("Overview sheet A11 is 'Summary'", function () { + expect(cell(sheets, "Overview", "A11")).to.equal("Summary"); + }); + + it("Overview sheet summary column headers are correct", function () { + expect(cell(sheets, "Overview", "A12")).to.equal("Total issues"); + expect(cell(sheets, "Overview", "B12")).to.equal("Violations"); + expect(cell(sheets, "Overview", "C12")).to.equal("Needs review"); + expect(cell(sheets, "Overview", "D12")).to.equal("Recommendations"); + expect(cell(sheets, "Overview", "E12")).to.equal("Archived"); + }); + + it("Scan summary sheet A1 is 'Page title'", function () { + expect(cell(sheets, "Scan summary", "A1")).to.equal("Page title"); + }); + + it("Issue summary sheet A1 is 'Issue summary'", function () { + expect(cell(sheets, "Issue summary", "A1")).to.equal("Issue summary"); + }); + + it("Issues sheet header row has correct column names", function () { + expect(cell(sheets, "Issues", "A1")).to.equal("Page title"); + expect(cell(sheets, "Issues", "B1")).to.equal("Page URL"); + expect(cell(sheets, "Issues", "C1")).to.equal("Scan label"); + expect(cell(sheets, "Issues", "N1")).to.equal("Help"); + }); + + it("Definition of fields sheet A1 is 'Definition of fields'", function () { + expect(cell(sheets, "Definition of fields", "A1")).to.equal("Definition of fields"); + }); +}); diff --git a/cypress-accessibility-checker/package-lock.json b/cypress-accessibility-checker/package-lock.json index 7cf6367c2..485df639d 100644 --- a/cypress-accessibility-checker/package-lock.json +++ b/cypress-accessibility-checker/package-lock.json @@ -16,6 +16,7 @@ "microdiff": "^1.5.0" }, "devDependencies": { + "adm-zip": "^0.5.9", "cypress": "^15.9.0", "eslint": "^8.4.1", "eslint-plugin-cypress": "^2.12.1", @@ -30,7 +31,7 @@ }, "peerDependenciesMeta": { "write-excel-file": { - "optional": true + "optional": false } } }, @@ -344,6 +345,16 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/adm-zip": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", + "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -1494,6 +1505,13 @@ "reusify": "^1.0.4" } }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT", + "peer": true + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3963,6 +3981,19 @@ "dev": true, "license": "ISC" }, + "node_modules/write-excel-file": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/write-excel-file/-/write-excel-file-4.1.1.tgz", + "integrity": "sha512-MUnCnNtQrcZek832ZcU24uU0rSphFmKPD1DvIjXOlygVb93CV7Tme6H3jUTkxsMmjB2W7HIzERzjqTi5kui71A==", + "license": "MIT", + "peer": true, + "dependencies": { + "fflate": "^0.8.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ws": { "version": "7.5.13", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", diff --git a/cypress-accessibility-checker/package.json b/cypress-accessibility-checker/package.json index dc75d69c8..13bdb8635 100644 --- a/cypress-accessibility-checker/package.json +++ b/cypress-accessibility-checker/package.json @@ -31,15 +31,16 @@ ], "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { - "cypress": "^13.2.0 || ^15", + "cypress": "^13.2.0 || ^15", "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { + }, + "peerDependenciesMeta": { "write-excel-file": { - "optional": true + "optional": true } - }, + }, "devDependencies": { + "adm-zip": "^0.5.9", "cypress": "^15.9.0", "eslint": "^8.4.1", "eslint-plugin-cypress": "^2.12.1", @@ -49,9 +50,9 @@ "start-server-and-test": "^2.0.0" }, "dependencies": { - "axios": "^1.7.9", - "@ibm/telemetry-js": "^1.9.1", - "microdiff": "^1.5.0", - "js-yaml": "^4.2.0" + "@ibm/telemetry-js": "^1.9.1", + "axios": "^1.7.9", + "js-yaml": "^4.2.0", + "microdiff": "^1.5.0" } } diff --git a/cypress-accessibility-checker/test/.achecker.yml b/cypress-accessibility-checker/test/.achecker.yml index 91625aa57..e406e7559 100644 --- a/cypress-accessibility-checker/test/.achecker.yml +++ b/cypress-accessibility-checker/test/.achecker.yml @@ -64,6 +64,9 @@ label: # Default: results outputFolder: results +# optional - Disable timestamp in output filenames for deterministic test paths +outputFilenameTimestamp: false + # optional - Where the baseline results should be loaded from # Default: baselines baselineFolder: baselines \ No newline at end of file diff --git a/cypress-accessibility-checker/test/cypress.config.js b/cypress-accessibility-checker/test/cypress.config.js index 71089dc2d..b6e566bcc 100644 --- a/cypress-accessibility-checker/test/cypress.config.js +++ b/cypress-accessibility-checker/test/cypress.config.js @@ -1,13 +1,91 @@ const { defineConfig } = require('cypress') +const AdmZip = require('adm-zip') +const fs = require('fs') +const path = require('path') + +// --------------------------------------------------------------------------- +// Helper — parse XLSX cell value using adm-zip (server-side only) +// --------------------------------------------------------------------------- +function readXlsxCell(filePath, sheetName, cellRef) { + const zip = new AdmZip(filePath) + + // Map sheetName → file via workbook.xml + workbook.xml.rels + // write-excel-file emits r:id before name, so extract attrs independently. + const wbXml = zip.getEntry('xl/workbook.xml').getData().toString('utf8') + const relsXml = zip.getEntry('xl/_rels/workbook.xml.rels').getData().toString('utf8') + + let rId = null + const sheetTagRe = /)/g + let sm + while ((sm = sheetTagRe.exec(wbXml)) !== null) { + const nameM = /name="([^"]+)"/.exec(sm[1]) + const ridM = /r:id="([^"]+)"/.exec(sm[1]) + if (nameM && nameM[1] === sheetName && ridM) { rId = ridM[1]; break } + } + if (!rId) throw new Error(`Sheet "${sheetName}" not found in workbook`) + + const relMatch = new RegExp(`]+Id="${rId}"[^>]+Target="([^"]+)"`).exec(relsXml) + if (!relMatch) throw new Error(`Relationship ${rId} not found`) + const target = relMatch[1] // e.g. "worksheets/sheet3.xml" + + // Read sharedStrings + const ssEntry = zip.getEntry('xl/sharedStrings.xml') + const sharedStrings = [] + if (ssEntry) { + const ssXml = ssEntry.getData().toString('utf8') + const siRe = /([\s\S]*?)<\/si>/g + let m + while ((m = siRe.exec(ssXml)) !== null) { + let text = '' + const tRe = /]*>([^<]*)<\/t>/g + let tm + while ((tm = tRe.exec(m[1])) !== null) text += tm[1] + sharedStrings.push(text) + } + } + + // Parse cell — handle both and ... forms + const col = cellRef.charCodeAt(0) - 65 // A→0 + const row = parseInt(cellRef.slice(1)) - 1 // 0-based + const sheetXml = zip.getEntry(`xl/${target}`).getData().toString('utf8') + + const cellRe = /|>([\s\S]*?)<\/c>)/g + let cm + while ((cm = cellRe.exec(sheetXml)) !== null) { + if (parseInt(cm[2]) - 1 !== row) continue + let c = 0 + for (const ch of cm[1]) c = c * 26 + (ch.charCodeAt(0) - 64) + if (c - 1 !== col) continue + const inner = cm[4] ?? '' + const vMatch = /([^<]*)<\/v>/.exec(inner) + if (!vMatch) return '' + if (/t="s"/.test(cm[3])) return sharedStrings[parseInt(vMatch[1])] ?? '' + return vMatch[1] + } + return '' +} module.exports = defineConfig({ e2e: { - // We've imported your old cypress plugins here. - // You may want to clean this up later by importing these. setupNodeEvents(on, config) { on('task', { - accessibilityChecker: require('../plugin') - }); + accessibilityChecker: require('../plugin'), + readXlsxCell({ filePath, sheetName, cellRef }) { + return readXlsxCell(filePath, sheetName, cellRef) + }, + xlsxSheetExists({ filePath, sheetName }) { + const zip = new AdmZip(filePath) + const wbXml = zip.getEntry('xl/workbook.xml').getData().toString('utf8') + // Simple presence check — attribute order doesn't matter here + return wbXml.includes(`name="${sheetName}"`) + }, + fileExists(filePath) { + return fs.existsSync(filePath) + }, + resolveXlsxPath({ folder, filename }) { + return path.resolve(process.cwd(), folder, filename) + }, + }) }, baseUrl: 'http://localhost:8080/test/sample-html', }, diff --git a/cypress-accessibility-checker/test/cypress/e2e/achecker-xlsx.cy.js b/cypress-accessibility-checker/test/cypress/e2e/achecker-xlsx.cy.js new file mode 100644 index 000000000..9090221ab --- /dev/null +++ b/cypress-accessibility-checker/test/cypress/e2e/achecker-xlsx.cy.js @@ -0,0 +1,86 @@ +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +/// + +// Helper: assert a cell in the XLSX via the server-side task. +function assertCell(xlsxPath, sheet, cellRef, expected) { + cy.task('readXlsxCell', { filePath: xlsxPath, sheetName: sheet, cellRef }) + .should('equal', expected); +} + +context('XLSX report generation', () => { + let xlsxPath; + + before(() => { + // Run a scan to populate the reporter, then flush via onRunComplete. + cy.visit('no-violations.html') + .getCompliance('xlsx-report-test') + .then(() => { + cy.task('accessibilityChecker', { task: 'onRunComplete', data: {} }); + }); + + // Resolve the XLSX path from the outputFolder declared in .achecker.yml + cy.task('resolveXlsxPath', { folder: 'results', filename: 'results.xlsx' }) + .then((p) => { xlsxPath = p; }); + }); + + it('XLSX file is created', () => { + cy.task('fileExists', xlsxPath).should('be.true'); + }); + + it('contains the expected sheet names', () => { + for (const sheet of ['Overview', 'Scan summary', 'Issue summary', 'Issues', 'Definition of fields']) { + cy.task('xlsxSheetExists', { filePath: xlsxPath, sheetName: sheet }) + .should('be.true', `Expected sheet "${sheet}" to exist`); + } + }); + + it('Overview A1 is "Accessibility Scan Report"', () => { + assertCell(xlsxPath, 'Overview', 'A1', 'Accessibility Scan Report'); + }); + + it('Overview A11 is "Summary"', () => { + assertCell(xlsxPath, 'Overview', 'A11', 'Summary'); + }); + + it('Overview summary column headers are correct', () => { + assertCell(xlsxPath, 'Overview', 'A12', 'Total issues'); + assertCell(xlsxPath, 'Overview', 'B12', 'Violations'); + assertCell(xlsxPath, 'Overview', 'C12', 'Needs review'); + assertCell(xlsxPath, 'Overview', 'D12', 'Recommendations'); + assertCell(xlsxPath, 'Overview', 'E12', 'Archived'); + }); + + it('Scan summary A1 is "Page title"', () => { + assertCell(xlsxPath, 'Scan summary', 'A1', 'Page title'); + }); + + it('Issue summary A1 is "Issue summary"', () => { + assertCell(xlsxPath, 'Issue summary', 'A1', 'Issue summary'); + }); + + it('Issues sheet header columns are correct', () => { + assertCell(xlsxPath, 'Issues', 'A1', 'Page title'); + assertCell(xlsxPath, 'Issues', 'B1', 'Page URL'); + assertCell(xlsxPath, 'Issues', 'C1', 'Scan label'); + assertCell(xlsxPath, 'Issues', 'N1', 'Help'); + }); + + it('Definition of fields A1 is "Definition of fields"', () => { + assertCell(xlsxPath, 'Definition of fields', 'A1', 'Definition of fields'); + }); +}); diff --git a/vitest-accessibility-checker/package-lock.json b/vitest-accessibility-checker/package-lock.json index 7c4017d63..43fca678b 100644 --- a/vitest-accessibility-checker/package-lock.json +++ b/vitest-accessibility-checker/package-lock.json @@ -19,6 +19,7 @@ "@vitest/browser": "^4.1.6", "@vitest/browser-playwright": "^4.1.6", "@vitest/ui": "^4.1.6", + "adm-zip": "^0.5.18", "eslint": "^8.4.1", "http-server": "^14.1.1", "playwright": "^1.40.0", @@ -33,7 +34,7 @@ }, "peerDependenciesMeta": { "write-excel-file": { - "optional": true + "optional": false } } }, @@ -722,6 +723,16 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/adm-zip": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", + "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -1353,7 +1364,6 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", - "dev": true, "license": "MIT" }, "node_modules/file-entry-cache": { @@ -3415,6 +3425,19 @@ "dev": true, "license": "ISC" }, + "node_modules/write-excel-file": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/write-excel-file/-/write-excel-file-4.1.1.tgz", + "integrity": "sha512-MUnCnNtQrcZek832ZcU24uU0rSphFmKPD1DvIjXOlygVb93CV7Tme6H3jUTkxsMmjB2W7HIzERzjqTi5kui71A==", + "license": "MIT", + "peer": true, + "dependencies": { + "fflate": "^0.8.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ws": { "version": "8.21.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", diff --git a/vitest-accessibility-checker/package.json b/vitest-accessibility-checker/package.json index 1aa34ddac..6b983966e 100644 --- a/vitest-accessibility-checker/package.json +++ b/vitest-accessibility-checker/package.json @@ -7,6 +7,7 @@ "scripts": { "lint": "eslint .", "test": "npm run build:common && vitest run --config=test/vitest.config.js", + "test:node": "npm run build:common && vitest run --config=test/vitest.node.config.mjs", "test:ui": "npm run build:common && vitest --ui --config=test/vitest.config.js", "test:start-http": "http-server -c-1 --silent", "build:common": "cd ../common/module && npm run build && cd ../../vitest-accessibility-checker && shx rm -rf ./src/lib/common && shx cp -R ../common/module/dist/cjs ./src/lib/common", @@ -45,6 +46,7 @@ "@vitest/browser": "^4.1.6", "@vitest/browser-playwright": "^4.1.6", "@vitest/ui": "^4.1.6", + "adm-zip": "^0.5.18", "eslint": "^8.4.1", "http-server": "^14.1.1", "playwright": "^1.40.0", @@ -59,4 +61,4 @@ "js-yaml": "^4.2.0", "microdiff": "^1.5.0" } -} \ No newline at end of file +} diff --git a/vitest-accessibility-checker/test/src/achecker-xlsx.test.js b/vitest-accessibility-checker/test/src/achecker-xlsx.test.js new file mode 100644 index 000000000..4abfa1872 --- /dev/null +++ b/vitest-accessibility-checker/test/src/achecker-xlsx.test.js @@ -0,0 +1,190 @@ +/** + * Copyright IBM Corp. 2026 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Node-side XLSX reporter test. + * + * Runs in a Node (forks) pool so it can use fs/adm-zip directly. + * Exercises ACReporterXLSX.generateSummary() end-to-end and verifies + * the structure of the produced XLSX file. + */ + +import { describe, it, expect, beforeAll, afterAll } from 'vitest' +import fs from 'fs' +import path from 'path' +import os from 'os' +import AdmZip from 'adm-zip' +import { ACReporterXLSX } from '../../src/lib/common/report/ACReporterXLSX.js' + +// --------------------------------------------------------------------------- +// XLSX parser — identical helper to the one in the mocha test +// --------------------------------------------------------------------------- +function readXlsxSheets(filePath) { + const zip = new AdmZip(filePath) + // write-excel-file emits r:id before name, so extract each attribute independently. + const wbXml = zip.getEntry('xl/workbook.xml').getData().toString('utf8') + const relsXml = zip.getEntry('xl/_rels/workbook.xml.rels').getData().toString('utf8') + + const sheetNames = [] + const sheetRe = /)/g + let m + while ((m = sheetRe.exec(wbXml)) !== null) { + const nameM = /name="([^"]+)"/.exec(m[1]) + const ridM = /r:id="([^"]+)"/.exec(m[1]) + if (nameM && ridM) sheetNames.push({ name: nameM[1], rId: ridM[1] }) + } + + const relMap = {} + const relRe = /]+Id="([^"]+)"[^>]+Target="([^"]+)"/g + while ((m = relRe.exec(relsXml)) !== null) relMap[m[1]] = m[2] + + const ssEntry = zip.getEntry('xl/sharedStrings.xml') + const sharedStrings = [] + if (ssEntry) { + const ssXml = ssEntry.getData().toString('utf8') + const siRe = /([\s\S]*?)<\/si>/g + while ((m = siRe.exec(ssXml)) !== null) { + let text = '' + const tRe = /]*>([^<]*)<\/t>/g + let tm + while ((tm = tRe.exec(m[1])) !== null) text += tm[1] + sharedStrings.push(text) + } + } + + const result = {} + for (const { name, rId } of sheetNames) { + const target = relMap[rId] + const sheetEntry = zip.getEntry(`xl/${target}`) + if (!sheetEntry) continue + // Use a sparse array indexed by actual Excel row number (1-based → 0-based). + // The regex handles both self-closing () and content (...) forms. + const sheetXml = sheetEntry.getData().toString('utf8') + const rows = [] + const cellRe = /|>([\s\S]*?)<\/c>)/g + let cm + while ((cm = cellRe.exec(sheetXml)) !== null) { + let col = 0 + for (const ch of cm[1]) col = col * 26 + (ch.charCodeAt(0) - 64) + col -= 1 + const rowNum = parseInt(cm[2]) - 1 // 0-based + if (!rows[rowNum]) rows[rowNum] = [] + const inner = cm[4] ?? '' // undefined for self-closing tags + const vMatch = /([^<]*)<\/v>/.exec(inner) + if (vMatch) { + rows[rowNum][col] = /t="s"/.test(cm[3]) ? (sharedStrings[parseInt(vMatch[1])] ?? '') : vMatch[1] + } + } + result[name] = rows + } + return result +} + +function cell(sheets, sheetName, ref) { + const col = ref.charCodeAt(0) - 65 + const row = parseInt(ref.slice(1)) - 1 + return sheets[sheetName]?.[row]?.[col] ?? '' +} + +// --------------------------------------------------------------------------- +// Minimal stub data — compressed array format expected by uncompressReport() +// Indices: [startScan, url, pageTitle, label, scanProfile, numExecuted, +// scanTime, ruleArchive, policies, reportLevels, issues[], counts] +// --------------------------------------------------------------------------- +function makeCompressedReport() { + return [ + Date.now(), // 0 startScan + 'http://localhost/test.html', // 1 url + 'XLSX vitest test page', // 2 pageTitle + 'vitest-xlsx-test', // 3 label + '', // 4 scanProfile + 0, // 5 numExecuted + 0, // 6 scanTime + 'Latest', // 7 ruleArchive + ['IBM_Accessibility'], // 8 policies + ['violation', 'potentialviolation', 'recommendation', 'potentialrecommendation', 'manual'], // 9 reportLevels + [], // 10 issues (compressed results) + { violation: 0, potentialviolation: 0, manual: 0, recommendation: 0, potentialrecommendation: 0, ignored: 0 }, // 11 counts + ] +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- +describe('XLSX report generation (vitest/Node)', () => { + let outputFolder + let xlsxPath + let sheets + + beforeAll(async () => { + outputFolder = fs.mkdtempSync(path.join(os.tmpdir(), 'vitest-xlsx-')) + + const config = { + toolID: '4.0.0-test', + ruleArchiveLabel: 'Latest Deployment', + policies: ['IBM_Accessibility'], + outputFolder, + outputFilenameTimestamp: false, + } + + const reporter = new ACReporterXLSX() + const summaryData = [makeCompressedReport()] + const rulesets = [] + + const { summary } = await reporter.generateSummary(config, rulesets, Date.now(), summaryData) + xlsxPath = path.join(outputFolder, 'results.xlsx') + await summary(xlsxPath) + + expect(fs.existsSync(xlsxPath), `XLSX file not created at ${xlsxPath}`).toBe(true) + sheets = readXlsxSheets(xlsxPath) + }) + + afterAll(() => { + fs.rmSync(outputFolder, { recursive: true, force: true }) + }) + + it('contains all expected sheet names', () => { + expect(Object.keys(sheets)).toEqual( + expect.arrayContaining(['Overview', 'Scan summary', 'Issue summary', 'Issues', 'Definition of fields']) + ) + }) + + it('Overview A1 is "Accessibility Scan Report"', () => { + expect(cell(sheets, 'Overview', 'A1')).toBe('Accessibility Scan Report') + }) + + it('Overview A11 is "Summary"', () => { + expect(cell(sheets, 'Overview', 'A11')).toBe('Summary') + }) + + it('Overview summary column headers are correct', () => { + expect(cell(sheets, 'Overview', 'A12')).toBe('Total issues') + expect(cell(sheets, 'Overview', 'B12')).toBe('Violations') + expect(cell(sheets, 'Overview', 'C12')).toBe('Needs review') + expect(cell(sheets, 'Overview', 'D12')).toBe('Recommendations') + expect(cell(sheets, 'Overview', 'E12')).toBe('Archived') + }) + + it('Scan summary A1 is "Page title"', () => { + expect(cell(sheets, 'Scan summary', 'A1')).toBe('Page title') + }) + + it('Issue summary A1 is "Issue summary"', () => { + expect(cell(sheets, 'Issue summary', 'A1')).toBe('Issue summary') + }) + + it('Issues sheet header row is correct', () => { + expect(cell(sheets, 'Issues', 'A1')).toBe('Page title') + expect(cell(sheets, 'Issues', 'B1')).toBe('Page URL') + expect(cell(sheets, 'Issues', 'C1')).toBe('Scan label') + expect(cell(sheets, 'Issues', 'N1')).toBe('Help') + }) + + it('Definition of fields A1 is "Definition of fields"', () => { + expect(cell(sheets, 'Definition of fields', 'A1')).toBe('Definition of fields') + }) +}) diff --git a/vitest-accessibility-checker/test/vitest.node.config.mjs b/vitest-accessibility-checker/test/vitest.node.config.mjs new file mode 100644 index 000000000..06cc9aa94 --- /dev/null +++ b/vitest-accessibility-checker/test/vitest.node.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig } from 'vitest/config'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** + * Vitest config for Node-side tests (reporter output, XLSX generation, etc.) + * Runs in a forked Node process so fs, adm-zip, etc. are available. + */ +export default defineConfig({ + root: __dirname, + test: { + include: ['src/achecker-xlsx.test.js'], + pool: 'forks', + }, +}); From 8cf5d12b57a82cfd3d15884ac7c765311dba169b Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 13:03:03 -0500 Subject: [PATCH 07/12] fix(xlsx): guard division by zero in Scan summary % columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit counts.elements can be 0 (or undefined) when a page has no elements to check. Dividing by zero produces NaN which write-excel-file writes as NaN — illegal OOXML that triggers Excel's corruption-repair dialog. Guard both percentage columns: return 0 when counts.elements is 0. --- .../cjs/lib/common/report/ACReporterXLSX.js | 779 ++++++++++++++++++ .../src/lib/common/report/ACReporterXLSX.js | 779 ++++++++++++++++++ .../mjs/lib/common/report/ACReporterXLSX.js | 744 +++++++++++++++++ .../module/dist/cjs/report/ACReporterXLSX.js | 779 ++++++++++++++++++ .../module/dist/mjs/report/ACReporterXLSX.js | 744 +++++++++++++++++ common/module/src/report/ACReporterXLSX.ts | 4 +- .../src/lib/common/report/ACReporterXLSX.js | 779 ++++++++++++++++++ .../src/lib/common/report/ACReporterXLSX.js | 779 ++++++++++++++++++ .../src/lib/common/report/ACReporterXLSX.js | 779 ++++++++++++++++++ 9 files changed, 6164 insertions(+), 2 deletions(-) create mode 100644 accessibility-checker/src/cjs/lib/common/report/ACReporterXLSX.js create mode 100644 accessibility-checker/src/lib/common/report/ACReporterXLSX.js create mode 100644 accessibility-checker/src/mjs/lib/common/report/ACReporterXLSX.js create mode 100644 common/module/dist/cjs/report/ACReporterXLSX.js create mode 100644 common/module/dist/mjs/report/ACReporterXLSX.js create mode 100644 cypress-accessibility-checker/src/lib/common/report/ACReporterXLSX.js create mode 100644 karma-accessibility-checker/src/lib/common/report/ACReporterXLSX.js create mode 100644 vitest-accessibility-checker/src/lib/common/report/ACReporterXLSX.js diff --git a/accessibility-checker/src/cjs/lib/common/report/ACReporterXLSX.js b/accessibility-checker/src/cjs/lib/common/report/ACReporterXLSX.js new file mode 100644 index 000000000..82f85d19f --- /dev/null +++ b/accessibility-checker/src/cjs/lib/common/report/ACReporterXLSX.js @@ -0,0 +1,779 @@ +"use strict"; +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ACReporterXLSX = void 0; +const IConfig_js_1 = require("../config/IConfig.js"); +const IGuideline_js_1 = require("../engine/IGuideline.js"); +const IRule_js_1 = require("../engine/IRule.js"); +const ReporterManager_js_1 = require("./ReporterManager.js"); +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => { var _a; return (_a = module.default) !== null && _a !== void 0 ? _a : module; }) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000" }, opts); +} +// Helper: bordered cell +function borderedCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin" }, opts); +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +function injectTableIntoFile(filePath, issueRowCount) { + return __awaiter(this, void 0, void 0, function* () { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch (_a) { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); + }); +} +class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + generateSummary(config, rulesets, endReport, summaryData) { + return __awaiter(this, void 0, void 0, function* () { + let storedReport = ReporterManager_js_1.ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: (filename) => __awaiter(this, void 0, void 0, function* () { + const writeExcelFile = yield loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + yield writeExcelFile(sheets).toFile(filename); + yield injectTableIntoFile(filename, issueRowCount); + }) + }; + }); + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = Object.assign(Object.assign({}, headerStyle), { align: "center", wrap: true }); + const data = []; + // Row 1: header row + data.push([ + Object.assign(Object.assign({ value: "Page title" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Page url" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Scan label" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Violations" }, countHeaderStyle), { backgroundColor: "#E4AAAF", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Needs review" }, countHeaderStyle), { backgroundColor: "#F4E08A", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Recommendations" }, countHeaderStyle), { backgroundColor: "#96A9D7", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Archived" }, countHeaderStyle), { backgroundColor: "#FFFFFF", textColor: "#000000" }), + Object.assign({ value: "% elements without violations" }, countHeaderStyle), + Object.assign({ value: "% elements without violations or items to review" }, countHeaderStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = Object.assign(Object.assign({}, textStyle), { align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }); + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.label }, textStyle), { align: "left" }), + Object.assign({ value: counts.violation }, numStyle), + Object.assign({ value: counts.potentialviolation + counts.manual }, numStyle), + Object.assign({ value: counts.recommendation + counts.potentialrecommendation }, numStyle), + Object.assign({ value: counts.ignored }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0 }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0 }, numStyle), + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== IRule_js_1.eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.potentialviolation || issue.level === IConfig_js_1.eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.recommendation || issue.level === IConfig_js_1.eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + Object.assign({ value: "Page title" }, hStyle), + Object.assign({ value: "Page URL" }, hStyle), + Object.assign({ value: "Scan label" }, hStyle), + Object.assign({ value: "Issue ID" }, hStyle), + Object.assign({ value: "Issue type" }, hStyle), + Object.assign({ value: "Toolkit level" }, hStyle), + Object.assign({ value: "Checkpoint" }, hStyle), + Object.assign({ value: "WCAG level" }, hStyle), + Object.assign({ value: "Rule" }, hStyle), + Object.assign({ value: "Issue" }, hStyle), + Object.assign({ value: "Element" }, hStyle), + Object.assign({ value: "Code" }, hStyle), + Object.assign({ value: "Xpath" }, hStyle), + Object.assign({ value: "Help" }, hStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.label }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}` }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: polInfo.tkLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: cpStrs.join("; ") }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: wcagLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.ruleId }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.message.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.get_element(item.snippet) }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.snippet.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.path.dom }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.help }, dStyle), { align: "left", alignVertical: "center" }), + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + Object.assign(Object.assign({ value: "Definition of fields" }, titleStyle), { height: 36, columnSpan: 2 }), + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + Object.assign(Object.assign({ value: "Scan summary and Issue summary" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + Object.assign(Object.assign({ value: "Issues" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +exports.ACReporterXLSX = ACReporterXLSX; +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file diff --git a/accessibility-checker/src/lib/common/report/ACReporterXLSX.js b/accessibility-checker/src/lib/common/report/ACReporterXLSX.js new file mode 100644 index 000000000..82f85d19f --- /dev/null +++ b/accessibility-checker/src/lib/common/report/ACReporterXLSX.js @@ -0,0 +1,779 @@ +"use strict"; +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ACReporterXLSX = void 0; +const IConfig_js_1 = require("../config/IConfig.js"); +const IGuideline_js_1 = require("../engine/IGuideline.js"); +const IRule_js_1 = require("../engine/IRule.js"); +const ReporterManager_js_1 = require("./ReporterManager.js"); +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => { var _a; return (_a = module.default) !== null && _a !== void 0 ? _a : module; }) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000" }, opts); +} +// Helper: bordered cell +function borderedCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin" }, opts); +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +function injectTableIntoFile(filePath, issueRowCount) { + return __awaiter(this, void 0, void 0, function* () { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch (_a) { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); + }); +} +class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + generateSummary(config, rulesets, endReport, summaryData) { + return __awaiter(this, void 0, void 0, function* () { + let storedReport = ReporterManager_js_1.ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: (filename) => __awaiter(this, void 0, void 0, function* () { + const writeExcelFile = yield loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + yield writeExcelFile(sheets).toFile(filename); + yield injectTableIntoFile(filename, issueRowCount); + }) + }; + }); + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = Object.assign(Object.assign({}, headerStyle), { align: "center", wrap: true }); + const data = []; + // Row 1: header row + data.push([ + Object.assign(Object.assign({ value: "Page title" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Page url" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Scan label" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Violations" }, countHeaderStyle), { backgroundColor: "#E4AAAF", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Needs review" }, countHeaderStyle), { backgroundColor: "#F4E08A", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Recommendations" }, countHeaderStyle), { backgroundColor: "#96A9D7", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Archived" }, countHeaderStyle), { backgroundColor: "#FFFFFF", textColor: "#000000" }), + Object.assign({ value: "% elements without violations" }, countHeaderStyle), + Object.assign({ value: "% elements without violations or items to review" }, countHeaderStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = Object.assign(Object.assign({}, textStyle), { align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }); + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.label }, textStyle), { align: "left" }), + Object.assign({ value: counts.violation }, numStyle), + Object.assign({ value: counts.potentialviolation + counts.manual }, numStyle), + Object.assign({ value: counts.recommendation + counts.potentialrecommendation }, numStyle), + Object.assign({ value: counts.ignored }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0 }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0 }, numStyle), + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== IRule_js_1.eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.potentialviolation || issue.level === IConfig_js_1.eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.recommendation || issue.level === IConfig_js_1.eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + Object.assign({ value: "Page title" }, hStyle), + Object.assign({ value: "Page URL" }, hStyle), + Object.assign({ value: "Scan label" }, hStyle), + Object.assign({ value: "Issue ID" }, hStyle), + Object.assign({ value: "Issue type" }, hStyle), + Object.assign({ value: "Toolkit level" }, hStyle), + Object.assign({ value: "Checkpoint" }, hStyle), + Object.assign({ value: "WCAG level" }, hStyle), + Object.assign({ value: "Rule" }, hStyle), + Object.assign({ value: "Issue" }, hStyle), + Object.assign({ value: "Element" }, hStyle), + Object.assign({ value: "Code" }, hStyle), + Object.assign({ value: "Xpath" }, hStyle), + Object.assign({ value: "Help" }, hStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.label }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}` }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: polInfo.tkLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: cpStrs.join("; ") }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: wcagLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.ruleId }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.message.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.get_element(item.snippet) }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.snippet.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.path.dom }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.help }, dStyle), { align: "left", alignVertical: "center" }), + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + Object.assign(Object.assign({ value: "Definition of fields" }, titleStyle), { height: 36, columnSpan: 2 }), + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + Object.assign(Object.assign({ value: "Scan summary and Issue summary" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + Object.assign(Object.assign({ value: "Issues" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +exports.ACReporterXLSX = ACReporterXLSX; +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file diff --git a/accessibility-checker/src/mjs/lib/common/report/ACReporterXLSX.js b/accessibility-checker/src/mjs/lib/common/report/ACReporterXLSX.js new file mode 100644 index 000000000..bc0b71165 --- /dev/null +++ b/accessibility-checker/src/mjs/lib/common/report/ACReporterXLSX.js @@ -0,0 +1,744 @@ +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +import { eRuleLevel } from "../config/IConfig.js"; +import { eToolkitLevel } from "../engine/IGuideline.js"; +import { eRuleConfidence } from "../engine/IRule.js"; +import { ReporterManager } from "./ReporterManager.js"; +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = import(/* webpackIgnore: true */ moduleName) + .then(module => module.default ?? module) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return { + value, + fontFamily: "Calibri", + fontSize: 12, + textColor: "#000000", + ...opts + }; +} +// Helper: bordered cell +function borderedCell(value, opts) { + return { + value, + fontFamily: "Calibri", + fontSize: 12, + textColor: "#000000", + borderColor: "#A6A6A6", + borderStyle: "thin", + ...opts + }; +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +async function injectTableIntoFile(filePath, issueRowCount) { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); +} +export class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + async generateSummary(config, rulesets, endReport, summaryData) { + let storedReport = ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: async (filename) => { + const writeExcelFile = await loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + await writeExcelFile(sheets).toFile(filename); + await injectTableIntoFile(filename, issueRowCount); + } + }; + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = { ...headerStyle, align: "center", wrap: true }; + const data = []; + // Row 1: header row + data.push([ + { value: "Page title", ...headerStyle, align: "left" }, + { value: "Page url", ...headerStyle, align: "left" }, + { value: "Scan label", ...headerStyle, align: "left" }, + { value: "Violations", ...countHeaderStyle, backgroundColor: "#E4AAAF", textColor: "#000000" }, + { value: "Needs review", ...countHeaderStyle, backgroundColor: "#F4E08A", textColor: "#000000" }, + { value: "Recommendations", ...countHeaderStyle, backgroundColor: "#96A9D7", textColor: "#000000" }, + { value: "Archived", ...countHeaderStyle, backgroundColor: "#FFFFFF", textColor: "#000000" }, + { value: "% elements without violations", ...countHeaderStyle }, + { value: "% elements without violations or items to review", ...countHeaderStyle }, + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = { ...textStyle, align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }; + data.push([ + { value: storedScan.pageTitle, ...textStyle, align: "left" }, + { value: storedScan.engineReport.summary.URL, ...textStyle, align: "left" }, + { value: storedScan.label, ...textStyle, align: "left" }, + { value: counts.violation, ...numStyle }, + { value: counts.potentialviolation + counts.manual, ...numStyle }, + { value: counts.recommendation + counts.potentialrecommendation, ...numStyle }, + { value: counts.ignored, ...numStyle }, + { value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0, ...numStyle }, + { value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0, ...numStyle }, + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === eRuleLevel.potentialviolation || issue.level === eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === eRuleLevel.recommendation || issue.level === eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + { value: "Page title", ...hStyle }, + { value: "Page URL", ...hStyle }, + { value: "Scan label", ...hStyle }, + { value: "Issue ID", ...hStyle }, + { value: "Issue type", ...hStyle }, + { value: "Toolkit level", ...hStyle }, + { value: "Checkpoint", ...hStyle }, + { value: "WCAG level", ...hStyle }, + { value: "Rule", ...hStyle }, + { value: "Issue", ...hStyle }, + { value: "Element", ...hStyle }, + { value: "Code", ...hStyle }, + { value: "Xpath", ...hStyle }, + { value: "Help", ...hStyle }, + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + { value: storedScan.pageTitle, ...dStyle, align: "left", alignVertical: "center" }, + { value: storedScan.engineReport.summary.URL, ...dStyle, align: "left", alignVertical: "center" }, + { value: storedScan.label, ...dStyle, align: "center", alignVertical: "center" }, + { value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom), ...dStyle, align: "left", alignVertical: "center" }, + { value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}`, ...dStyle, align: "center", alignVertical: "center" }, + { value: polInfo.tkLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" }, + { value: cpStrs.join("; "), ...dStyle, align: "left", alignVertical: "center" }, + { value: wcagLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" }, + { value: item.ruleId, ...dStyle, align: "left", alignVertical: "center" }, + { value: item.message.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" }, + { value: ACReporterXLSX.get_element(item.snippet), ...dStyle, align: "center", alignVertical: "center" }, + { value: item.snippet.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" }, + { value: item.path.dom, ...dStyle, align: "left", alignVertical: "center" }, + { value: item.help, ...dStyle, align: "left", alignVertical: "center" }, + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + { value: "Definition of fields", ...titleStyle, height: 36, columnSpan: 2 }, + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + { value: "Scan summary and Issue summary", ...sectionStyle, height: 20, columnSpan: 2 }, + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + { value: "Field", ...subHeaderStyle, height: 16 }, + { value: "Definition", ...subHeaderStyle }, + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + { value: row.key1, ...dataStyle }, + { value: row.key2, ...dataStyle }, + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + { value: "Issues", ...sectionStyle, height: 20, columnSpan: 2 }, + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + { value: "Field", ...subHeaderStyle, height: 16 }, + { value: "Definition", ...subHeaderStyle }, + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + { value: row.key1, ...dataStyle }, + { value: row.key2, ...dataStyle }, + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file diff --git a/common/module/dist/cjs/report/ACReporterXLSX.js b/common/module/dist/cjs/report/ACReporterXLSX.js new file mode 100644 index 000000000..82f85d19f --- /dev/null +++ b/common/module/dist/cjs/report/ACReporterXLSX.js @@ -0,0 +1,779 @@ +"use strict"; +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ACReporterXLSX = void 0; +const IConfig_js_1 = require("../config/IConfig.js"); +const IGuideline_js_1 = require("../engine/IGuideline.js"); +const IRule_js_1 = require("../engine/IRule.js"); +const ReporterManager_js_1 = require("./ReporterManager.js"); +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => { var _a; return (_a = module.default) !== null && _a !== void 0 ? _a : module; }) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000" }, opts); +} +// Helper: bordered cell +function borderedCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin" }, opts); +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +function injectTableIntoFile(filePath, issueRowCount) { + return __awaiter(this, void 0, void 0, function* () { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch (_a) { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); + }); +} +class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + generateSummary(config, rulesets, endReport, summaryData) { + return __awaiter(this, void 0, void 0, function* () { + let storedReport = ReporterManager_js_1.ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: (filename) => __awaiter(this, void 0, void 0, function* () { + const writeExcelFile = yield loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + yield writeExcelFile(sheets).toFile(filename); + yield injectTableIntoFile(filename, issueRowCount); + }) + }; + }); + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = Object.assign(Object.assign({}, headerStyle), { align: "center", wrap: true }); + const data = []; + // Row 1: header row + data.push([ + Object.assign(Object.assign({ value: "Page title" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Page url" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Scan label" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Violations" }, countHeaderStyle), { backgroundColor: "#E4AAAF", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Needs review" }, countHeaderStyle), { backgroundColor: "#F4E08A", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Recommendations" }, countHeaderStyle), { backgroundColor: "#96A9D7", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Archived" }, countHeaderStyle), { backgroundColor: "#FFFFFF", textColor: "#000000" }), + Object.assign({ value: "% elements without violations" }, countHeaderStyle), + Object.assign({ value: "% elements without violations or items to review" }, countHeaderStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = Object.assign(Object.assign({}, textStyle), { align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }); + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.label }, textStyle), { align: "left" }), + Object.assign({ value: counts.violation }, numStyle), + Object.assign({ value: counts.potentialviolation + counts.manual }, numStyle), + Object.assign({ value: counts.recommendation + counts.potentialrecommendation }, numStyle), + Object.assign({ value: counts.ignored }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0 }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0 }, numStyle), + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== IRule_js_1.eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.potentialviolation || issue.level === IConfig_js_1.eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.recommendation || issue.level === IConfig_js_1.eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + Object.assign({ value: "Page title" }, hStyle), + Object.assign({ value: "Page URL" }, hStyle), + Object.assign({ value: "Scan label" }, hStyle), + Object.assign({ value: "Issue ID" }, hStyle), + Object.assign({ value: "Issue type" }, hStyle), + Object.assign({ value: "Toolkit level" }, hStyle), + Object.assign({ value: "Checkpoint" }, hStyle), + Object.assign({ value: "WCAG level" }, hStyle), + Object.assign({ value: "Rule" }, hStyle), + Object.assign({ value: "Issue" }, hStyle), + Object.assign({ value: "Element" }, hStyle), + Object.assign({ value: "Code" }, hStyle), + Object.assign({ value: "Xpath" }, hStyle), + Object.assign({ value: "Help" }, hStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.label }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}` }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: polInfo.tkLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: cpStrs.join("; ") }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: wcagLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.ruleId }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.message.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.get_element(item.snippet) }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.snippet.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.path.dom }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.help }, dStyle), { align: "left", alignVertical: "center" }), + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + Object.assign(Object.assign({ value: "Definition of fields" }, titleStyle), { height: 36, columnSpan: 2 }), + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + Object.assign(Object.assign({ value: "Scan summary and Issue summary" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + Object.assign(Object.assign({ value: "Issues" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +exports.ACReporterXLSX = ACReporterXLSX; +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file diff --git a/common/module/dist/mjs/report/ACReporterXLSX.js b/common/module/dist/mjs/report/ACReporterXLSX.js new file mode 100644 index 000000000..bc0b71165 --- /dev/null +++ b/common/module/dist/mjs/report/ACReporterXLSX.js @@ -0,0 +1,744 @@ +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +import { eRuleLevel } from "../config/IConfig.js"; +import { eToolkitLevel } from "../engine/IGuideline.js"; +import { eRuleConfidence } from "../engine/IRule.js"; +import { ReporterManager } from "./ReporterManager.js"; +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = import(/* webpackIgnore: true */ moduleName) + .then(module => module.default ?? module) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return { + value, + fontFamily: "Calibri", + fontSize: 12, + textColor: "#000000", + ...opts + }; +} +// Helper: bordered cell +function borderedCell(value, opts) { + return { + value, + fontFamily: "Calibri", + fontSize: 12, + textColor: "#000000", + borderColor: "#A6A6A6", + borderStyle: "thin", + ...opts + }; +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +async function injectTableIntoFile(filePath, issueRowCount) { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); +} +export class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + async generateSummary(config, rulesets, endReport, summaryData) { + let storedReport = ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: async (filename) => { + const writeExcelFile = await loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + await writeExcelFile(sheets).toFile(filename); + await injectTableIntoFile(filename, issueRowCount); + } + }; + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = { ...headerStyle, align: "center", wrap: true }; + const data = []; + // Row 1: header row + data.push([ + { value: "Page title", ...headerStyle, align: "left" }, + { value: "Page url", ...headerStyle, align: "left" }, + { value: "Scan label", ...headerStyle, align: "left" }, + { value: "Violations", ...countHeaderStyle, backgroundColor: "#E4AAAF", textColor: "#000000" }, + { value: "Needs review", ...countHeaderStyle, backgroundColor: "#F4E08A", textColor: "#000000" }, + { value: "Recommendations", ...countHeaderStyle, backgroundColor: "#96A9D7", textColor: "#000000" }, + { value: "Archived", ...countHeaderStyle, backgroundColor: "#FFFFFF", textColor: "#000000" }, + { value: "% elements without violations", ...countHeaderStyle }, + { value: "% elements without violations or items to review", ...countHeaderStyle }, + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = { ...textStyle, align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }; + data.push([ + { value: storedScan.pageTitle, ...textStyle, align: "left" }, + { value: storedScan.engineReport.summary.URL, ...textStyle, align: "left" }, + { value: storedScan.label, ...textStyle, align: "left" }, + { value: counts.violation, ...numStyle }, + { value: counts.potentialviolation + counts.manual, ...numStyle }, + { value: counts.recommendation + counts.potentialrecommendation, ...numStyle }, + { value: counts.ignored, ...numStyle }, + { value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0, ...numStyle }, + { value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0, ...numStyle }, + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === eRuleLevel.potentialviolation || issue.level === eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === eRuleLevel.recommendation || issue.level === eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + { value: "Page title", ...hStyle }, + { value: "Page URL", ...hStyle }, + { value: "Scan label", ...hStyle }, + { value: "Issue ID", ...hStyle }, + { value: "Issue type", ...hStyle }, + { value: "Toolkit level", ...hStyle }, + { value: "Checkpoint", ...hStyle }, + { value: "WCAG level", ...hStyle }, + { value: "Rule", ...hStyle }, + { value: "Issue", ...hStyle }, + { value: "Element", ...hStyle }, + { value: "Code", ...hStyle }, + { value: "Xpath", ...hStyle }, + { value: "Help", ...hStyle }, + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + { value: storedScan.pageTitle, ...dStyle, align: "left", alignVertical: "center" }, + { value: storedScan.engineReport.summary.URL, ...dStyle, align: "left", alignVertical: "center" }, + { value: storedScan.label, ...dStyle, align: "center", alignVertical: "center" }, + { value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom), ...dStyle, align: "left", alignVertical: "center" }, + { value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}`, ...dStyle, align: "center", alignVertical: "center" }, + { value: polInfo.tkLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" }, + { value: cpStrs.join("; "), ...dStyle, align: "left", alignVertical: "center" }, + { value: wcagLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" }, + { value: item.ruleId, ...dStyle, align: "left", alignVertical: "center" }, + { value: item.message.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" }, + { value: ACReporterXLSX.get_element(item.snippet), ...dStyle, align: "center", alignVertical: "center" }, + { value: item.snippet.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" }, + { value: item.path.dom, ...dStyle, align: "left", alignVertical: "center" }, + { value: item.help, ...dStyle, align: "left", alignVertical: "center" }, + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + { value: "Definition of fields", ...titleStyle, height: 36, columnSpan: 2 }, + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + { value: "Scan summary and Issue summary", ...sectionStyle, height: 20, columnSpan: 2 }, + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + { value: "Field", ...subHeaderStyle, height: 16 }, + { value: "Definition", ...subHeaderStyle }, + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + { value: row.key1, ...dataStyle }, + { value: row.key2, ...dataStyle }, + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + { value: "Issues", ...sectionStyle, height: 20, columnSpan: 2 }, + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + { value: "Field", ...subHeaderStyle, height: 16 }, + { value: "Definition", ...subHeaderStyle }, + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + { value: row.key1, ...dataStyle }, + { value: row.key2, ...dataStyle }, + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file diff --git a/common/module/src/report/ACReporterXLSX.ts b/common/module/src/report/ACReporterXLSX.ts index a4baaf886..6d86e6f80 100644 --- a/common/module/src/report/ACReporterXLSX.ts +++ b/common/module/src/report/ACReporterXLSX.ts @@ -396,8 +396,8 @@ export class ACReporterXLSX implements IReporter { { value: counts.potentialviolation + counts.manual, ...numStyle }, { value: counts.recommendation + counts.potentialrecommendation, ...numStyle }, { value: counts.ignored, ...numStyle }, - { value: parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)), ...numStyle }, - { value: parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)), ...numStyle }, + { value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0, ...numStyle }, + { value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0, ...numStyle }, ]); } diff --git a/cypress-accessibility-checker/src/lib/common/report/ACReporterXLSX.js b/cypress-accessibility-checker/src/lib/common/report/ACReporterXLSX.js new file mode 100644 index 000000000..82f85d19f --- /dev/null +++ b/cypress-accessibility-checker/src/lib/common/report/ACReporterXLSX.js @@ -0,0 +1,779 @@ +"use strict"; +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ACReporterXLSX = void 0; +const IConfig_js_1 = require("../config/IConfig.js"); +const IGuideline_js_1 = require("../engine/IGuideline.js"); +const IRule_js_1 = require("../engine/IRule.js"); +const ReporterManager_js_1 = require("./ReporterManager.js"); +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => { var _a; return (_a = module.default) !== null && _a !== void 0 ? _a : module; }) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000" }, opts); +} +// Helper: bordered cell +function borderedCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin" }, opts); +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +function injectTableIntoFile(filePath, issueRowCount) { + return __awaiter(this, void 0, void 0, function* () { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch (_a) { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); + }); +} +class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + generateSummary(config, rulesets, endReport, summaryData) { + return __awaiter(this, void 0, void 0, function* () { + let storedReport = ReporterManager_js_1.ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: (filename) => __awaiter(this, void 0, void 0, function* () { + const writeExcelFile = yield loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + yield writeExcelFile(sheets).toFile(filename); + yield injectTableIntoFile(filename, issueRowCount); + }) + }; + }); + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = Object.assign(Object.assign({}, headerStyle), { align: "center", wrap: true }); + const data = []; + // Row 1: header row + data.push([ + Object.assign(Object.assign({ value: "Page title" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Page url" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Scan label" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Violations" }, countHeaderStyle), { backgroundColor: "#E4AAAF", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Needs review" }, countHeaderStyle), { backgroundColor: "#F4E08A", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Recommendations" }, countHeaderStyle), { backgroundColor: "#96A9D7", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Archived" }, countHeaderStyle), { backgroundColor: "#FFFFFF", textColor: "#000000" }), + Object.assign({ value: "% elements without violations" }, countHeaderStyle), + Object.assign({ value: "% elements without violations or items to review" }, countHeaderStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = Object.assign(Object.assign({}, textStyle), { align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }); + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.label }, textStyle), { align: "left" }), + Object.assign({ value: counts.violation }, numStyle), + Object.assign({ value: counts.potentialviolation + counts.manual }, numStyle), + Object.assign({ value: counts.recommendation + counts.potentialrecommendation }, numStyle), + Object.assign({ value: counts.ignored }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0 }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0 }, numStyle), + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== IRule_js_1.eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.potentialviolation || issue.level === IConfig_js_1.eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.recommendation || issue.level === IConfig_js_1.eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + Object.assign({ value: "Page title" }, hStyle), + Object.assign({ value: "Page URL" }, hStyle), + Object.assign({ value: "Scan label" }, hStyle), + Object.assign({ value: "Issue ID" }, hStyle), + Object.assign({ value: "Issue type" }, hStyle), + Object.assign({ value: "Toolkit level" }, hStyle), + Object.assign({ value: "Checkpoint" }, hStyle), + Object.assign({ value: "WCAG level" }, hStyle), + Object.assign({ value: "Rule" }, hStyle), + Object.assign({ value: "Issue" }, hStyle), + Object.assign({ value: "Element" }, hStyle), + Object.assign({ value: "Code" }, hStyle), + Object.assign({ value: "Xpath" }, hStyle), + Object.assign({ value: "Help" }, hStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.label }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}` }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: polInfo.tkLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: cpStrs.join("; ") }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: wcagLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.ruleId }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.message.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.get_element(item.snippet) }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.snippet.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.path.dom }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.help }, dStyle), { align: "left", alignVertical: "center" }), + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + Object.assign(Object.assign({ value: "Definition of fields" }, titleStyle), { height: 36, columnSpan: 2 }), + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + Object.assign(Object.assign({ value: "Scan summary and Issue summary" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + Object.assign(Object.assign({ value: "Issues" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +exports.ACReporterXLSX = ACReporterXLSX; +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file diff --git a/karma-accessibility-checker/src/lib/common/report/ACReporterXLSX.js b/karma-accessibility-checker/src/lib/common/report/ACReporterXLSX.js new file mode 100644 index 000000000..82f85d19f --- /dev/null +++ b/karma-accessibility-checker/src/lib/common/report/ACReporterXLSX.js @@ -0,0 +1,779 @@ +"use strict"; +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ACReporterXLSX = void 0; +const IConfig_js_1 = require("../config/IConfig.js"); +const IGuideline_js_1 = require("../engine/IGuideline.js"); +const IRule_js_1 = require("../engine/IRule.js"); +const ReporterManager_js_1 = require("./ReporterManager.js"); +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => { var _a; return (_a = module.default) !== null && _a !== void 0 ? _a : module; }) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000" }, opts); +} +// Helper: bordered cell +function borderedCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin" }, opts); +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +function injectTableIntoFile(filePath, issueRowCount) { + return __awaiter(this, void 0, void 0, function* () { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch (_a) { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); + }); +} +class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + generateSummary(config, rulesets, endReport, summaryData) { + return __awaiter(this, void 0, void 0, function* () { + let storedReport = ReporterManager_js_1.ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: (filename) => __awaiter(this, void 0, void 0, function* () { + const writeExcelFile = yield loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + yield writeExcelFile(sheets).toFile(filename); + yield injectTableIntoFile(filename, issueRowCount); + }) + }; + }); + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = Object.assign(Object.assign({}, headerStyle), { align: "center", wrap: true }); + const data = []; + // Row 1: header row + data.push([ + Object.assign(Object.assign({ value: "Page title" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Page url" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Scan label" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Violations" }, countHeaderStyle), { backgroundColor: "#E4AAAF", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Needs review" }, countHeaderStyle), { backgroundColor: "#F4E08A", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Recommendations" }, countHeaderStyle), { backgroundColor: "#96A9D7", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Archived" }, countHeaderStyle), { backgroundColor: "#FFFFFF", textColor: "#000000" }), + Object.assign({ value: "% elements without violations" }, countHeaderStyle), + Object.assign({ value: "% elements without violations or items to review" }, countHeaderStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = Object.assign(Object.assign({}, textStyle), { align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }); + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.label }, textStyle), { align: "left" }), + Object.assign({ value: counts.violation }, numStyle), + Object.assign({ value: counts.potentialviolation + counts.manual }, numStyle), + Object.assign({ value: counts.recommendation + counts.potentialrecommendation }, numStyle), + Object.assign({ value: counts.ignored }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0 }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0 }, numStyle), + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== IRule_js_1.eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.potentialviolation || issue.level === IConfig_js_1.eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.recommendation || issue.level === IConfig_js_1.eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + Object.assign({ value: "Page title" }, hStyle), + Object.assign({ value: "Page URL" }, hStyle), + Object.assign({ value: "Scan label" }, hStyle), + Object.assign({ value: "Issue ID" }, hStyle), + Object.assign({ value: "Issue type" }, hStyle), + Object.assign({ value: "Toolkit level" }, hStyle), + Object.assign({ value: "Checkpoint" }, hStyle), + Object.assign({ value: "WCAG level" }, hStyle), + Object.assign({ value: "Rule" }, hStyle), + Object.assign({ value: "Issue" }, hStyle), + Object.assign({ value: "Element" }, hStyle), + Object.assign({ value: "Code" }, hStyle), + Object.assign({ value: "Xpath" }, hStyle), + Object.assign({ value: "Help" }, hStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.label }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}` }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: polInfo.tkLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: cpStrs.join("; ") }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: wcagLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.ruleId }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.message.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.get_element(item.snippet) }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.snippet.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.path.dom }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.help }, dStyle), { align: "left", alignVertical: "center" }), + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + Object.assign(Object.assign({ value: "Definition of fields" }, titleStyle), { height: 36, columnSpan: 2 }), + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + Object.assign(Object.assign({ value: "Scan summary and Issue summary" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + Object.assign(Object.assign({ value: "Issues" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +exports.ACReporterXLSX = ACReporterXLSX; +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file diff --git a/vitest-accessibility-checker/src/lib/common/report/ACReporterXLSX.js b/vitest-accessibility-checker/src/lib/common/report/ACReporterXLSX.js new file mode 100644 index 000000000..82f85d19f --- /dev/null +++ b/vitest-accessibility-checker/src/lib/common/report/ACReporterXLSX.js @@ -0,0 +1,779 @@ +"use strict"; +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ACReporterXLSX = void 0; +const IConfig_js_1 = require("../config/IConfig.js"); +const IGuideline_js_1 = require("../engine/IGuideline.js"); +const IRule_js_1 = require("../engine/IRule.js"); +const ReporterManager_js_1 = require("./ReporterManager.js"); +// Lazy-load write-excel-file — will be null if not installed +let writeExcelLoadPromise = null; +let writeExcelWarningShown = false; +function loadWriteExcel() { + if (!writeExcelLoadPromise) { + const moduleName = "write-excel-file/node"; + writeExcelLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => { var _a; return (_a = module.default) !== null && _a !== void 0 ? _a : module; }) + .catch(() => null); + } + return writeExcelLoadPromise; +} +function showWriteExcelWarning() { + if (!writeExcelWarningShown) { + writeExcelWarningShown = true; + console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled."); + console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file"); + } +} +function dropDupes(arr) { + let dupes = {}; + return arr.filter(item => { + if (item.toString() in dupes) { + return false; + } + { + return dupes[item.toString()] = true; + } + }); +} +// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB) +function argbToHex(argb) { + if (!argb || argb.length < 6) + return "#000000"; + // Strip leading alpha if 8 chars + const rgb = argb.length === 8 ? argb.slice(2) : argb; + return `#${rgb}`; +} +// Helper: cell with dark purple header style +function headerCell(value, columnSpan) { + const cell = { + value, + backgroundColor: "#403151", + textColor: "#FFFFFF", + fontFamily: "Calibri", + fontSize: 16, + alignVertical: "center", + align: "left", + height: 36, + }; + if (columnSpan && columnSpan > 1) + cell.columnSpan = columnSpan; + return cell; +} +// Helper: standard data cell +function dataCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000" }, opts); +} +// Helper: bordered cell +function borderedCell(value, opts) { + return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin" }, opts); +} +// ─── XLSX table injection ────────────────────────────────────────────────────── +// write-excel-file has no native Excel table API. We post-process the output +// file: unzip it with Node's built-in zlib, inject the table definition XML, +// wire the sheet to reference it, and re-zip. +// +// The Issues sheet is always sheet index 3 (0-based) → sheetId "4". +// TableStyleMedium2 + showRowStripes matches the original ExcelJS output. +const ISSUES_SHEET_ID = "4"; +const ISSUES_TABLE_ID = "1"; +const ISSUES_COL_COUNT = 14; +const ISSUES_COL_NAMES = [ + "Page title", "Page URL", "Scan label", "Issue ID", "Issue type", + "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue", + "Element", "Code", "Xpath", "Help", +]; +function buildTableXml(rowCount) { + const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1]; + const ref = `A1:${lastCol}${rowCount}`; + const cols = ISSUES_COL_NAMES.map((name, i) => ``).join(""); + return `` + + `` + + `` + + `${cols}` + + `` + + `
`; +} +function injectTableIntoFile(filePath, issueRowCount) { + return __awaiter(this, void 0, void 0, function* () { + let AdmZip; + try { + // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module. + // The try/catch ensures graceful degradation if adm-zip is not installed. + AdmZip = require(/* webpackIgnore: true */ "adm-zip"); + } + catch (_a) { + // adm-zip not available — skip table injection gracefully + return; + } + const zip = new AdmZip(filePath); + // 1. Add xl/tables/table1.xml + const tableXml = buildTableXml(issueRowCount); + zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8")); + // 2. Patch xl/worksheets/_rels/sheet4.xml.rels + const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`; + const relsEntry = zip.getEntry(relsPath); + const tableRel = ``; + if (relsEntry) { + const existing = relsEntry.getData().toString("utf8"); + zip.updateFile(relsPath, Buffer.from(existing.replace("", tableRel + ""), "utf8")); + } + else { + zip.addFile(relsPath, Buffer.from(`` + + `` + + tableRel + ``, "utf8")); + } + // 3. Patch xl/worksheets/sheet4.xml — add before + const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`; + const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8"); + zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("", ``), "utf8")); + // 4. Patch [Content_Types].xml + const ctPath = "[Content_Types].xml"; + const ctXml = zip.getEntry(ctPath).getData().toString("utf8"); + zip.updateFile(ctPath, Buffer.from(ctXml.replace("", ``), "utf8")); + zip.writeZip(filePath); + }); +} +class ACReporterXLSX { + name() { + return "xlsx"; + } + generateReport(_reportData) { + } + generateSummary(config, rulesets, endReport, summaryData) { + return __awaiter(this, void 0, void 0, function* () { + let storedReport = ReporterManager_js_1.ReporterManager.uncompressReport(summaryData[0]); + let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id)); + let policyInfo = {}; + for (const rs of cfgRulesets) { + for (const cp of rs.checkpoints) { + for (const rule of cp.rules) { + policyInfo[rule.id] = policyInfo[rule.id] || { + tkLevels: [], + cps: [] + }; + policyInfo[rule.id].tkLevels.push(rule.toolkitLevel); + policyInfo[rule.id].cps.push(cp); + } + } + } + for (const ruleId in policyInfo) { + policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels); + policyInfo[ruleId].tkLevels.sort(); + } + let startScan = new Date(storedReport.engineReport.summary.startScan); + let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`; + if (config.outputFilenameTimestamp === false) { + reportFilename = `results.xlsx`; + } + return { + summaryPath: reportFilename, + summary: (filename) => __awaiter(this, void 0, void 0, function* () { + const writeExcelFile = yield loadWriteExcel(); + if (!writeExcelFile) { + showWriteExcelWarning(); + return; + } + const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData); + const issueRowCount = issuesSheet._issueRowCount; + delete issuesSheet._issueRowCount; + const sheets = [ + ACReporterXLSX.createOverviewSheet(config, summaryData), + ACReporterXLSX.createScanSummarySheet(config, summaryData), + ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData), + issuesSheet, + ACReporterXLSX.createDefinitionsSheet(), + ]; + yield writeExcelFile(sheets).toFile(filename); + yield injectTableIntoFile(filename, issueRowCount); + }) + }; + }); + } + static createOverviewSheet(config, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archived = 0; + let totalIssues = 0; + let startScan = 0; + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + if (startScan === 0) + startScan = storedScan.engineReport.summary.startScan; + const counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archived += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations + archived; + const columns = [ + { width: 15.1 }, + { width: 15.9 }, + { width: 16.23 }, + { width: 19.4 }, + { width: 15 }, + ]; + const rowData = [ + { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' }, + { key1: 'Version:', key2: config.toolID }, + { key1: 'Rule set:', key2: config.ruleArchiveLabel }, + { key1: 'Guidelines:', key2: config.policies.join(", ") }, + { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, + { key1: 'Scans:', key2: "" + compressedScans.length }, + ]; + const data = []; + // Row 1: Title spanning 5 cols + data.push([ + { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Rows 2–7: metadata key/value pairs + for (const row of rowData) { + data.push([ + dataCell(row.key1, { align: "left", height: 12 }), + { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 }, + null, null, null + ]); + } + // Row 8: blank spacer + data.push([null]); + // Row 9: blank spacer + data.push([null]); + // Row 10: blank spacer + data.push([null]); + // Row 11: "Summary" title spanning 5 cols + data.push([ + { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 }, + null, null, null, null + ]); + // Row 12: column headers + data.push([ + borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }), + borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }), + borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }), + borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }), + borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }), + ]); + // Row 13: values + data.push([ + borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }), + borderedCell(violations, { align: "center", alignVertical: "center" }), + borderedCell(needsReviews, { align: "center", alignVertical: "center" }), + borderedCell(recommendations, { align: "center", alignVertical: "center" }), + borderedCell(archived, { align: "center", alignVertical: "center" }), + ]); + return { data, sheet: "Overview", columns }; + } + static createScanSummarySheet(config, compressedScans) { + const columns = [ + { width: 27.0 }, + { width: 46.0 }, + { width: 20.17 }, + { width: 18.5 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + ]; + const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 }; + const countHeaderStyle = Object.assign(Object.assign({}, headerStyle), { align: "center", wrap: true }); + const data = []; + // Row 1: header row + data.push([ + Object.assign(Object.assign({ value: "Page title" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Page url" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Scan label" }, headerStyle), { align: "left" }), + Object.assign(Object.assign({ value: "Violations" }, countHeaderStyle), { backgroundColor: "#E4AAAF", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Needs review" }, countHeaderStyle), { backgroundColor: "#F4E08A", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Recommendations" }, countHeaderStyle), { backgroundColor: "#96A9D7", textColor: "#000000" }), + Object.assign(Object.assign({ value: "Archived" }, countHeaderStyle), { backgroundColor: "#FFFFFF", textColor: "#000000" }), + Object.assign({ value: "% elements without violations" }, countHeaderStyle), + Object.assign({ value: "% elements without violations or items to review" }, countHeaderStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + let counts = storedScan.engineReport.summary.counts; + const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true }; + const numStyle = Object.assign(Object.assign({}, textStyle), { align: "center", borderColor: "#A6A6A6", borderStyle: "thin" }); + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, textStyle), { align: "left" }), + Object.assign(Object.assign({ value: storedScan.label }, textStyle), { align: "left" }), + Object.assign({ value: counts.violation }, numStyle), + Object.assign({ value: counts.potentialviolation + counts.manual }, numStyle), + Object.assign({ value: counts.recommendation + counts.potentialrecommendation }, numStyle), + Object.assign({ value: counts.ignored }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0 }, numStyle), + Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0 }, numStyle), + ]); + } + return { data, sheet: "Scan summary", columns }; + } + static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) { + const rows = []; + // Level type title row (e.g. "Violations") + rows.push([ + { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 }, + { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + // Individual issue message rows, sorted descending by count + const rowArray = []; + for (const property in levelrowValues) { + rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]); + } + rowArray.sort((a, b) => b[1] - a[1]); + for (const [msg, count] of rowArray) { + rows.push([ + { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 }, + { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + } + return rows; + } + static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) { + const rows = []; + // Level title row (e.g. "Level 1 - the most essential...") + rows.push([ + { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues)); + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues)); + if (levelCounts[4] > 0) { + rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues)); + } + return rows; + } + static createIssueSummarySheet(config, policyInfo, compressedScans) { + let violations = 0; + let needsReviews = 0; + let recommendations = 0; + let archive = 0; + let totalIssues = 0; + for (let i = 0; i < compressedScans.length; i++) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScans[i]); + let counts = storedScan.engineReport.summary.counts; + violations += counts.violation; + needsReviews += counts.potentialviolation + counts.manual; + recommendations += counts.recommendation + counts.potentialrecommendation; + archive += counts.ignored; + } + totalIssues = violations + needsReviews + recommendations; + let level1Counts = [0, 0, 0, 0, 0]; + let level2Counts = [0, 0, 0, 0, 0]; + let level3Counts = [0, 0, 0, 0, 0]; + let level4Counts = [0, 0, 0, 0, 0]; + let level1V = []; + let level2V = []; + let level3V = []; + let level4V = []; + let level1NR = []; + let level2NR = []; + let level3NR = []; + let level4NR = []; + let level1R = []; + let level2R = []; + let level3R = []; + let level4R = []; + let level1A = []; + let level2A = []; + let level3A = []; + let level4A = []; + for (const compressedScan of compressedScans) { + let scan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const issue of scan.engineReport.results) { + if (!(issue.ruleId in policyInfo)) { + policyInfo[issue.ruleId] = { tkLevels: [], cps: [] }; + } + let levelCounts, levelV, levelNR, levelR, levelA; + const issuePolicyInfo = policyInfo[issue.ruleId]; + if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_ONE)) { + levelCounts = level1Counts; + levelV = level1V; + levelNR = level1NR; + levelR = level1R; + levelA = level1A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_TWO)) { + levelCounts = level2Counts; + levelV = level2V; + levelNR = level2NR; + levelR = level2R; + levelA = level2A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_THREE)) { + levelCounts = level3Counts; + levelV = level3V; + levelNR = level3NR; + levelR = level3R; + levelA = level3A; + } + else if (issuePolicyInfo.tkLevels.includes(IGuideline_js_1.eToolkitLevel.LEVEL_FOUR)) { + levelCounts = level4Counts; + levelV = level4V; + levelNR = level4NR; + levelR = level4R; + levelA = level4A; + } + if (issue.value[1] !== IRule_js_1.eRuleConfidence.PASS) { + ++levelCounts[0]; + } + if (issue.ignored) { + ++levelCounts[4]; + levelA.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.violation) { + ++levelCounts[1]; + levelV.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.potentialviolation || issue.level === IConfig_js_1.eRuleLevel.manual) { + ++levelCounts[2]; + levelNR.push(issue.message.substring(0, 32767)); + } + else if (issue.level === IConfig_js_1.eRuleLevel.recommendation || issue.level === IConfig_js_1.eRuleLevel.potentialrecommendation) { + ++levelCounts[3]; + levelR.push(issue.message.substring(0, 32767)); + } + } + } + // @ts-ignore + let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V); + // @ts-ignore + let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR); + // @ts-ignore + let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R); + // @ts-ignore + let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A); + // @ts-ignore + let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V); + // @ts-ignore + let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR); + // @ts-ignore + let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R); + // @ts-ignore + let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A); + // @ts-ignore + let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V); + // @ts-ignore + let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR); + // @ts-ignore + let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R); + // @ts-ignore + let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A); + // @ts-ignore + let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V); + // @ts-ignore + let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR); + // @ts-ignore + let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R); + // @ts-ignore + let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A); + const columns = [ + { width: 155.51 }, + { width: 21.16 }, + ]; + const data = []; + // Row 1: "Issue summary" title spanning 2 cols + data.push([ + { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 }, + null + ]); + // Row 2: description spanning 2 cols + data.push([ + { value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 }, + null + ]); + // Row 3: "Total issues found:" with value + data.push([ + { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 }, + { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" }, + ]); + // Row 4: "Number of issues" label + data.push([ + { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 }, + { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" }, + ]); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues)); + data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues)); + return { data, sheet: "Issue summary", columns }; + } + static createIssuesSheet(config, policyInfo, compressedScans) { + const valueMap = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + const columns = [ + { width: 18.0 }, + { width: 20.5 }, + { width: 21.0 }, + { width: 18.5 }, + { width: 17.0 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 17.17 }, + { width: 14.00 }, + { width: 17.17 }, + { width: 43.00 }, + { width: 17.17 }, + ]; + // Header and data row colors are intentionally omitted — the Excel table + // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring. + const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 }; + const data = []; + // Header row + data.push([ + Object.assign({ value: "Page title" }, hStyle), + Object.assign({ value: "Page URL" }, hStyle), + Object.assign({ value: "Scan label" }, hStyle), + Object.assign({ value: "Issue ID" }, hStyle), + Object.assign({ value: "Issue type" }, hStyle), + Object.assign({ value: "Toolkit level" }, hStyle), + Object.assign({ value: "Checkpoint" }, hStyle), + Object.assign({ value: "WCAG level" }, hStyle), + Object.assign({ value: "Rule" }, hStyle), + Object.assign({ value: "Issue" }, hStyle), + Object.assign({ value: "Element" }, hStyle), + Object.assign({ value: "Code" }, hStyle), + Object.assign({ value: "Xpath" }, hStyle), + Object.assign({ value: "Help" }, hStyle), + ]); + for (const compressedScan of compressedScans) { + let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan); + for (const item of storedScan.engineReport.results) { + if (!(item.ruleId in policyInfo)) { + policyInfo[item.ruleId] = { tkLevels: [], cps: [] }; + } + let polInfo = policyInfo[item.ruleId]; + let cps = polInfo.cps.filter(cp => { + let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId))); + return !!ruleInfo; + }); + let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel)); + wcagLevels.sort(); + let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`)); + cpStrs.sort(); + const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 }; + data.push([ + Object.assign(Object.assign({ value: storedScan.pageTitle }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: storedScan.label }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}` }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: polInfo.tkLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: cpStrs.join("; ") }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: wcagLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.ruleId }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.message.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: ACReporterXLSX.get_element(item.snippet) }, dStyle), { align: "center", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.snippet.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.path.dom }, dStyle), { align: "left", alignVertical: "center" }), + Object.assign(Object.assign({ value: item.help }, dStyle), { align: "left", alignVertical: "center" }), + ]); + } + } + return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length }; + } + static createDefinitionsSheet() { + const columns = [ + { width: 41.51 }, + { width: 119.51 }, + ]; + const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" }; + const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" }; + const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" }; + const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 }; + const summaryRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' }, + { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' }, + { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' }, + { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' }, + { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' }, + { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' } + ]; + const issuesRowData = [ + { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' }, + { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' }, + { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' }, + { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' }, + { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' }, + { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' }, + { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' }, + { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' }, + { key1: 'Issue', key2: 'Message describing the issue.' }, + { key1: 'Element', key2: 'Type of HTML element where the issue is found.' }, + { key1: 'Code', key2: 'Actual HTML element where the issue is found.' }, + { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' }, + { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' }, + ]; + const data = []; + // Row 1: "Definition of fields" title spanning 2 cols + data.push([ + Object.assign(Object.assign({ value: "Definition of fields" }, titleStyle), { height: 36, columnSpan: 2 }), + null + ]); + // Row 2: blank + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 3: "Scan summary and Issue summary" section header + data.push([ + Object.assign(Object.assign({ value: "Scan summary and Issue summary" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 4: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 5–12: scan summary definitions + for (const row of summaryRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + // Row 13: blank (separator between sections) — kept simple + data.push([{ value: null, height: 12, columnSpan: 2 }, null]); + // Row 14: "Issues" section header + data.push([ + Object.assign(Object.assign({ value: "Issues" }, sectionStyle), { height: 20, columnSpan: 2 }), + null + ]); + // Row 15: "Field / Definition" subheader + data.push([ + Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }), + Object.assign({ value: "Definition" }, subHeaderStyle), + ]); + // Rows 16–28: issues definitions + for (const row of issuesRowData) { + data.push([ + Object.assign({ value: row.key1 }, dataStyle), + Object.assign({ value: row.key2 }, dataStyle), + ]); + } + return { data, sheet: "Definition of fields", columns }; + } + static countDuplicatesInArray(array) { + let count = {}; + array.forEach(item => { + if (count[item]) { + //@ts-ignore + count[item] += 1; + return; + } + //@ts-ignore + count[item] = 1; + }); + return count; + } + static get_element(code) { + if (code) { + const ind_s = code.indexOf(' '); + const ind_br = code.indexOf('>'); + return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br); + } + return ''; + } + static format_date(timestamp) { + var date = new Date(timestamp); + return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" + + ("00" + date.getDate()).slice(-2) + "-" + + ("00" + date.getHours()).slice(-2) + "-" + + ("00" + date.getMinutes()).slice(-2) + "-" + + ("00" + date.getSeconds()).slice(-2); + } + // From https://github.com/darkskyapp/string-hash/blob/master/index.js + static stringHash(str) { + var hash = 5381, i = str.length; + while (i) { + hash = (hash * 33) ^ str.charCodeAt(--i); + } + return hash >>> 0; + } +} +exports.ACReporterXLSX = ACReporterXLSX; +//# sourceMappingURL=ACReporterXLSX.js.map \ No newline at end of file From dcab339804ed02c1735a4f4cc1294f04263c00ca Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 13:10:08 -0500 Subject: [PATCH 08/12] fix(ci): install write-excel-file before cypress run; guard adm-zip on missing file - test.yml: add 'npm install write-excel-file' step for cypress-accessibility-checker (peerDependencies are not auto-installed by npm install) - cypress.config.js: guard readXlsxCell and xlsxSheetExists tasks against missing file so tests fail with a clear message instead of ADM-ZIP crash --- .github/workflows/test.yml | 2 ++ cypress-accessibility-checker/test/cypress.config.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 653ac7e78..83f0d3a6c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -518,6 +518,8 @@ jobs: working-directory: common/module - run: npm install working-directory: cypress-accessibility-checker + - run: npm install write-excel-file + working-directory: cypress-accessibility-checker - run: npm run build:common working-directory: cypress-accessibility-checker - run: npm run test:start-http & diff --git a/cypress-accessibility-checker/test/cypress.config.js b/cypress-accessibility-checker/test/cypress.config.js index b6e566bcc..f86e1842e 100644 --- a/cypress-accessibility-checker/test/cypress.config.js +++ b/cypress-accessibility-checker/test/cypress.config.js @@ -71,9 +71,11 @@ module.exports = defineConfig({ on('task', { accessibilityChecker: require('../plugin'), readXlsxCell({ filePath, sheetName, cellRef }) { + if (!fs.existsSync(filePath)) throw new Error(`XLSX file not found: ${filePath}`) return readXlsxCell(filePath, sheetName, cellRef) }, xlsxSheetExists({ filePath, sheetName }) { + if (!fs.existsSync(filePath)) return false const zip = new AdmZip(filePath) const wbXml = zip.getEntry('xl/workbook.xml').getData().toString('utf8') // Simple presence check — attribute order doesn't matter here From 076dc4bbb303b8d1cbaf1634f843e164fa03a49a Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 13:11:05 -0500 Subject: [PATCH 09/12] fix(vitest): exclude node-only XLSX test from browser vitest config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit achecker-xlsx.test.js imports ACReporterXLSX (CJS) and adm-zip — both Node-only. The default include pattern was picking it up in the Chromium browser run causing 'does not provide an export named ACReporterXLSX'. Explicitly exclude it from vitest.config.js; it runs separately via vitest.node.config.mjs (pool: forks). --- vitest-accessibility-checker/test/vitest.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vitest-accessibility-checker/test/vitest.config.js b/vitest-accessibility-checker/test/vitest.config.js index b106fc882..58bac78a6 100644 --- a/vitest-accessibility-checker/test/vitest.config.js +++ b/vitest-accessibility-checker/test/vitest.config.js @@ -11,6 +11,8 @@ export default defineConfig({ root: __dirname, plugins: [accessibilityCheckerPlugin()], test: { + // Explicitly exclude the Node-only XLSX test (runs via vitest.node.config.mjs instead) + exclude: ['src/achecker-xlsx.test.js'], browser: { enabled: true, instances: [ From 9870259b0955d1fe2bf30a2c300c06b5cdad2990 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 13:21:35 -0500 Subject: [PATCH 10/12] fix(deps): move write-excel-file from peerDeps to deps in all checker packages peerDependencies are not auto-installed by npm install, causing 'write-excel-file is not installed' warnings in CI for cypress and vitest. Move write-excel-file to regular dependencies in: - accessibility-checker - cypress-accessibility-checker - vitest-accessibility-checker Remove the now-redundant explicit 'npm install write-excel-file' CI steps. --- .github/workflows/test.yml | 8 -------- accessibility-checker/package.json | 11 ++--------- cypress-accessibility-checker/package.json | 11 +++-------- vitest-accessibility-checker/package.json | 11 +++-------- 4 files changed, 8 insertions(+), 33 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 83f0d3a6c..07acf6022 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -145,8 +145,6 @@ jobs: working-directory: accessibility-checker - run: npx mocha -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.mjs working-directory: accessibility-checker - - run: npm install write-excel-file - working-directory: accessibility-checker - run: npx mocha --timeout 30000 -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs working-directory: accessibility-checker @@ -199,8 +197,6 @@ jobs: working-directory: accessibility-checker - run: npx mocha -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.mjs working-directory: accessibility-checker - - run: npm install write-excel-file - working-directory: accessibility-checker - run: npx mocha --timeout 30000 -R dot test/mocha/aChecker.Fast/aChecker.Scans/aChecker.XLSX.test.mjs working-directory: accessibility-checker @@ -518,8 +514,6 @@ jobs: working-directory: common/module - run: npm install working-directory: cypress-accessibility-checker - - run: npm install write-excel-file - working-directory: cypress-accessibility-checker - run: npm run build:common working-directory: cypress-accessibility-checker - run: npm run test:start-http & @@ -561,8 +555,6 @@ jobs: working-directory: vitest-accessibility-checker - run: npx playwright install chromium working-directory: vitest-accessibility-checker - - run: npm install write-excel-file - working-directory: vitest-accessibility-checker - run: npm run build:common working-directory: vitest-accessibility-checker - run: npx vitest run diff --git a/accessibility-checker/package.json b/accessibility-checker/package.json index f785d75a1..48e8f3d2d 100644 --- a/accessibility-checker/package.json +++ b/accessibility-checker/package.json @@ -22,20 +22,13 @@ "engines": { "node": ">=16" }, - "peerDependencies": { - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - } - }, "dependencies": { "adm-zip": "^0.5.9", "chromedriver": "*", "js-yaml": "^4.2.0", "microdiff": "^1.5.0", - "puppeteer": "^25.1.0" + "puppeteer": "^25.1.0", + "write-excel-file": "^4.1.1" }, "devDependencies": { "@ibm/telemetry-js": "^1.9.1", diff --git a/cypress-accessibility-checker/package.json b/cypress-accessibility-checker/package.json index 13bdb8635..f1e7d9e53 100644 --- a/cypress-accessibility-checker/package.json +++ b/cypress-accessibility-checker/package.json @@ -31,13 +31,7 @@ ], "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { - "cypress": "^13.2.0 || ^15", - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - } + "cypress": "^13.2.0 || ^15" }, "devDependencies": { "adm-zip": "^0.5.9", @@ -53,6 +47,7 @@ "@ibm/telemetry-js": "^1.9.1", "axios": "^1.7.9", "js-yaml": "^4.2.0", - "microdiff": "^1.5.0" + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" } } diff --git a/vitest-accessibility-checker/package.json b/vitest-accessibility-checker/package.json index 6b983966e..3516477f1 100644 --- a/vitest-accessibility-checker/package.json +++ b/vitest-accessibility-checker/package.json @@ -34,13 +34,7 @@ ], "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { - "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - } + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0" }, "devDependencies": { "@vitest/browser": "^4.1.6", @@ -59,6 +53,7 @@ "@ibm/telemetry-js": "^1.9.1", "axios": "^1.7.9", "js-yaml": "^4.2.0", - "microdiff": "^1.5.0" + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" } } From 54f4f35473944038b0edcc5a3c7f8b029be4bcb7 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 31 Aug 2026 13:26:37 -0500 Subject: [PATCH 11/12] fix(deps): move write-excel-file to regular deps everywhere; update READMEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move write-excel-file (and adm-zip in common/module) from peerDependencies to regular dependencies in all remaining packages: - common/module - accessibility-checker/src (published package manifest) - vitest-accessibility-checker/src (published package manifest) - karma-accessibility-checker Update all four READMEs to remove the 'Optional: XLSX Report Format' install instructions — XLSX is now included automatically. --- accessibility-checker/src/README.md | 10 ++-------- accessibility-checker/src/package.json | 11 ++--------- common/module/package.json | 16 +++------------- cypress-accessibility-checker/README.md | 10 ++-------- karma-accessibility-checker/README.md | 10 ++-------- karma-accessibility-checker/package.json | 11 ++--------- vitest-accessibility-checker/README.md | 10 ++-------- vitest-accessibility-checker/src/package.json | 11 +++-------- 8 files changed, 18 insertions(+), 71 deletions(-) diff --git a/accessibility-checker/src/README.md b/accessibility-checker/src/README.md index 3d03cf972..02cc1dd58 100644 --- a/accessibility-checker/src/README.md +++ b/accessibility-checker/src/README.md @@ -119,15 +119,9 @@ $ npm install -g accessibility-checker $ achecker ``` -## Optional: XLSX Report Format +## XLSX Report Format -If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: - -```bash -$ npm install --save-dev write-excel-file adm-zip -``` - -Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. +XLSX report format is included automatically — no additional installation required. ## Setup diff --git a/accessibility-checker/src/package.json b/accessibility-checker/src/package.json index 2b067e97b..0a49f46aa 100644 --- a/accessibility-checker/src/package.json +++ b/accessibility-checker/src/package.json @@ -28,18 +28,11 @@ "dependencies": { "@ibm/telemetry-js": "^1.9.1", "chromedriver": "*", - "microdiff": "^1.5.0", "js-yaml": "^4.2.0", - "puppeteer": "^25.1.0" - }, - "peerDependencies": { + "microdiff": "^1.5.0", + "puppeteer": "^25.1.0", "write-excel-file": "^4.1.1" }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - } - }, "repository": { "type": "git", "url": "https://github.com/IBMa/equal-access.git" diff --git a/common/module/package.json b/common/module/package.json index 2c74f20f7..2e1e23c12 100644 --- a/common/module/package.json +++ b/common/module/package.json @@ -22,19 +22,9 @@ "ts-node": "^10.9.1", "typescript": "^5.1.3" }, - "peerDependencies": { - "write-excel-file": "^4.1.1", - "adm-zip": "^0.5.9" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - }, - "adm-zip": { - "optional": true - } - }, "dependencies": { - "microdiff": "^1.5.0" + "adm-zip": "^0.5.9", + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" } } diff --git a/cypress-accessibility-checker/README.md b/cypress-accessibility-checker/README.md index 8ead43210..ab38eae4e 100644 --- a/cypress-accessibility-checker/README.md +++ b/cypress-accessibility-checker/README.md @@ -29,15 +29,9 @@ Install the package as a devDependency. npm install cypress-accessibility-checker --save-dev ``` -### Optional: XLSX Report Format +### XLSX Report Format -If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: - -```bash -npm install write-excel-file adm-zip --save-dev -``` - -Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. +XLSX report format is included automatically — no additional installation required. ## Configuration diff --git a/karma-accessibility-checker/README.md b/karma-accessibility-checker/README.md index f72309c12..42f091899 100644 --- a/karma-accessibility-checker/README.md +++ b/karma-accessibility-checker/README.md @@ -30,15 +30,9 @@ All bugs or issues related to the karma-accessibility-checker code can be create * [Node Version 22](https://nodejs.org/en/download/). -## Optional: XLSX Report Format +## XLSX Report Format -If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: - -```bash -$ npm install write-excel-file adm-zip -``` - -Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. +XLSX report format is included automatically — no additional installation required. ## Running Locally diff --git a/karma-accessibility-checker/package.json b/karma-accessibility-checker/package.json index d79f400ae..480ac02cb 100644 --- a/karma-accessibility-checker/package.json +++ b/karma-accessibility-checker/package.json @@ -43,19 +43,12 @@ ], "author": "Tom Brunet ", "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", - "peerDependencies": { - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - } - }, "dependencies": { "js-yaml": "4.3.0", "karma": "6.3.18", "karma-accessibility-checker": "file:package/karma-accessibility-checker", - "microdiff": "^1.5.0" + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" }, "devDependencies": { "adm-zip": "^0.5.9", diff --git a/vitest-accessibility-checker/README.md b/vitest-accessibility-checker/README.md index 703840869..0c58e8812 100644 --- a/vitest-accessibility-checker/README.md +++ b/vitest-accessibility-checker/README.md @@ -108,15 +108,9 @@ $ npm install $ npm run test:browser ``` -## Optional: XLSX Report Format +## XLSX Report Format -If you want to generate reports in XLSX format, install `write-excel-file` and `adm-zip` as additional dependencies: - -```bash -$ npm install --save-dev write-excel-file adm-zip -``` - -Without these packages installed, all other report formats (JSON, HTML, CSV) will work normally, but XLSX format will be disabled with a warning message. +XLSX report format is included automatically — no additional installation required. ## Known issues and workarounds diff --git a/vitest-accessibility-checker/src/package.json b/vitest-accessibility-checker/src/package.json index 6270ae9be..00dddc4ca 100644 --- a/vitest-accessibility-checker/src/package.json +++ b/vitest-accessibility-checker/src/package.json @@ -36,19 +36,14 @@ ], "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "peerDependencies": { - "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - } + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0" }, "dependencies": { "@ibm/telemetry-js": "^1.9.1", "axios": "^1.7.9", "js-yaml": "^4.2.0", - "microdiff": "^1.5.0" + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" }, "publishConfig": { "access": "public" From 8069925e3a2d3e7b396e1e82aeb8a92b2823024f Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 1 Sep 2026 13:11:51 -0500 Subject: [PATCH 12/12] Move adm-zip to dep --- .../package-lock.json | 12 ++--- common/module/package-lock.json | 49 +++++++++++++------ .../boilerplates/package-lock.json | 6 +-- .../package-lock.json | 24 +++------ cypress-accessibility-checker/package.json | 2 +- report-react/package-lock.json | 12 ++--- .../package-lock.json | 15 ++---- vitest-accessibility-checker/package.json | 2 +- .../src/package-lock.json | 29 ++++++++--- 9 files changed, 83 insertions(+), 68 deletions(-) diff --git a/accessibility-checker-extension/package-lock.json b/accessibility-checker-extension/package-lock.json index 66006903d..10164128b 100644 --- a/accessibility-checker-extension/package-lock.json +++ b/accessibility-checker-extension/package-lock.json @@ -2177,9 +2177,9 @@ } }, "node_modules/@internationalized/number": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.7.tgz", - "integrity": "sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==", + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.8.tgz", + "integrity": "sha512-8UmMFia46DUt+k97zKd9fKWXcWHR+k8ae3eYzILETuT2KbIvLyOfac7zesw+sJdRAAZ7Q9pM1Mk22aXp2LD0Ig==", "license": "Apache-2.0", "dependencies": { "@swc/helpers": "^0.5.0" @@ -4486,9 +4486,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.417", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz", - "integrity": "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ==", + "version": "1.5.419", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.419.tgz", + "integrity": "sha512-nHMPn8x4yCxCI0iSnL+LlHL5sUoUfjLXkcRIagZ4GBdrfFLFaiLNvzJWbJqZhFT9IAhw5tUSNlhggWN+otvp/A==", "license": "ISC" }, "node_modules/emoji-regex": { diff --git a/common/module/package-lock.json b/common/module/package-lock.json index d91205868..e24434006 100644 --- a/common/module/package-lock.json +++ b/common/module/package-lock.json @@ -9,7 +9,9 @@ "version": "1.0.0", "license": "SEE LICENSE in ../../LICENSE", "dependencies": { - "microdiff": "^1.5.0" + "adm-zip": "^0.5.9", + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" }, "devDependencies": { "@types/jest": "^29.5.2", @@ -22,18 +24,6 @@ }, "engines": { "node": ">=16" - }, - "peerDependencies": { - "adm-zip": "^0.5.9", - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "adm-zip": { - "optional": true - }, - "write-excel-file": { - "optional": true - } } }, "node_modules/@babel/code-frame": { @@ -1133,6 +1123,15 @@ "node": ">=0.4.0" } }, + "node_modules/adm-zip": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", + "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1706,9 +1705,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.417", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz", - "integrity": "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ==", + "version": "1.5.419", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.419.tgz", + "integrity": "sha512-nHMPn8x4yCxCI0iSnL+LlHL5sUoUfjLXkcRIagZ4GBdrfFLFaiLNvzJWbJqZhFT9IAhw5tUSNlhggWN+otvp/A==", "dev": true, "license": "ISC" }, @@ -1853,6 +1852,12 @@ "bser": "2.1.1" } }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4020,6 +4025,18 @@ "dev": true, "license": "ISC" }, + "node_modules/write-excel-file": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/write-excel-file/-/write-excel-file-4.1.1.tgz", + "integrity": "sha512-MUnCnNtQrcZek832ZcU24uU0rSphFmKPD1DvIjXOlygVb93CV7Tme6H3jUTkxsMmjB2W7HIzERzjqTi5kui71A==", + "license": "MIT", + "dependencies": { + "fflate": "^0.8.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", diff --git a/cypress-accessibility-checker/boilerplates/package-lock.json b/cypress-accessibility-checker/boilerplates/package-lock.json index 67ba2f6ff..6d89bb5b9 100644 --- a/cypress-accessibility-checker/boilerplates/package-lock.json +++ b/cypress-accessibility-checker/boilerplates/package-lock.json @@ -3601,9 +3601,9 @@ } }, "node_modules/systeminformation": { - "version": "5.33.6", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.6.tgz", - "integrity": "sha512-hMOQG/eRUzuopuYGGdl8ntkau0nEC7fOaRoTUg1RSr2GTQIk2VNa76DA0+ApajkGfzmcgAupgIP/vt+jtoe5EA==", + "version": "5.33.7", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.7.tgz", + "integrity": "sha512-ndIY+FxSMednjy1OAi7Av72fOPfaD2NMcwOS0uCLkX1F9GdqDn5eyHuMnTycjoabH5K2NqH1wPLBiaSbNbgQGg==", "dev": true, "license": "MIT", "os": [ diff --git a/cypress-accessibility-checker/package-lock.json b/cypress-accessibility-checker/package-lock.json index 485df639d..fd24f9094 100644 --- a/cypress-accessibility-checker/package-lock.json +++ b/cypress-accessibility-checker/package-lock.json @@ -11,12 +11,13 @@ "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "dependencies": { "@ibm/telemetry-js": "^1.9.1", + "adm-zip": "^0.5.9", "axios": "^1.7.9", "js-yaml": "^4.2.0", - "microdiff": "^1.5.0" + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" }, "devDependencies": { - "adm-zip": "^0.5.9", "cypress": "^15.9.0", "eslint": "^8.4.1", "eslint-plugin-cypress": "^2.12.1", @@ -26,13 +27,7 @@ "start-server-and-test": "^2.0.0" }, "peerDependencies": { - "cypress": "^13.2.0 || ^15", - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": false - } + "cypress": "^13.2.0 || ^15" } }, "node_modules/@cypress/request": { @@ -349,7 +344,6 @@ "version": "0.5.18", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0" @@ -1509,8 +1503,7 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/file-entry-cache": { "version": "6.0.1", @@ -3609,9 +3602,9 @@ } }, "node_modules/systeminformation": { - "version": "5.33.6", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.6.tgz", - "integrity": "sha512-hMOQG/eRUzuopuYGGdl8ntkau0nEC7fOaRoTUg1RSr2GTQIk2VNa76DA0+ApajkGfzmcgAupgIP/vt+jtoe5EA==", + "version": "5.33.7", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.7.tgz", + "integrity": "sha512-ndIY+FxSMednjy1OAi7Av72fOPfaD2NMcwOS0uCLkX1F9GdqDn5eyHuMnTycjoabH5K2NqH1wPLBiaSbNbgQGg==", "dev": true, "license": "MIT", "os": [ @@ -3986,7 +3979,6 @@ "resolved": "https://registry.npmjs.org/write-excel-file/-/write-excel-file-4.1.1.tgz", "integrity": "sha512-MUnCnNtQrcZek832ZcU24uU0rSphFmKPD1DvIjXOlygVb93CV7Tme6H3jUTkxsMmjB2W7HIzERzjqTi5kui71A==", "license": "MIT", - "peer": true, "dependencies": { "fflate": "^0.8.2" }, diff --git a/cypress-accessibility-checker/package.json b/cypress-accessibility-checker/package.json index f1e7d9e53..5ed1f1798 100644 --- a/cypress-accessibility-checker/package.json +++ b/cypress-accessibility-checker/package.json @@ -34,7 +34,6 @@ "cypress": "^13.2.0 || ^15" }, "devDependencies": { - "adm-zip": "^0.5.9", "cypress": "^15.9.0", "eslint": "^8.4.1", "eslint-plugin-cypress": "^2.12.1", @@ -45,6 +44,7 @@ }, "dependencies": { "@ibm/telemetry-js": "^1.9.1", + "adm-zip": "^0.5.9", "axios": "^1.7.9", "js-yaml": "^4.2.0", "microdiff": "^1.5.0", diff --git a/report-react/package-lock.json b/report-react/package-lock.json index f7d1c26af..70bc8d442 100644 --- a/report-react/package-lock.json +++ b/report-react/package-lock.json @@ -27,9 +27,9 @@ } }, "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.3.0.tgz", + "integrity": "sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==", "license": "MIT", "engines": { "node": ">=10" @@ -7747,9 +7747,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.417", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz", - "integrity": "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ==", + "version": "1.5.419", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.419.tgz", + "integrity": "sha512-nHMPn8x4yCxCI0iSnL+LlHL5sUoUfjLXkcRIagZ4GBdrfFLFaiLNvzJWbJqZhFT9IAhw5tUSNlhggWN+otvp/A==", "license": "ISC" }, "node_modules/emittery": { diff --git a/vitest-accessibility-checker/package-lock.json b/vitest-accessibility-checker/package-lock.json index 43fca678b..e34fee903 100644 --- a/vitest-accessibility-checker/package-lock.json +++ b/vitest-accessibility-checker/package-lock.json @@ -11,15 +11,16 @@ "license": "SEE LICENSE IN LICENSE from the 'equal-access' repository", "dependencies": { "@ibm/telemetry-js": "^1.9.1", + "adm-zip": "^0.5.18", "axios": "^1.7.9", "js-yaml": "^4.2.0", - "microdiff": "^1.5.0" + "microdiff": "^1.5.0", + "write-excel-file": "^4.1.1" }, "devDependencies": { "@vitest/browser": "^4.1.6", "@vitest/browser-playwright": "^4.1.6", "@vitest/ui": "^4.1.6", - "adm-zip": "^0.5.18", "eslint": "^8.4.1", "http-server": "^14.1.1", "playwright": "^1.40.0", @@ -29,13 +30,7 @@ "vitest": "^4.1.6" }, "peerDependencies": { - "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", - "write-excel-file": "^4.1.1" - }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": false - } + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0" } }, "node_modules/@blazediff/core": { @@ -727,7 +722,6 @@ "version": "0.5.18", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0" @@ -3430,7 +3424,6 @@ "resolved": "https://registry.npmjs.org/write-excel-file/-/write-excel-file-4.1.1.tgz", "integrity": "sha512-MUnCnNtQrcZek832ZcU24uU0rSphFmKPD1DvIjXOlygVb93CV7Tme6H3jUTkxsMmjB2W7HIzERzjqTi5kui71A==", "license": "MIT", - "peer": true, "dependencies": { "fflate": "^0.8.2" }, diff --git a/vitest-accessibility-checker/package.json b/vitest-accessibility-checker/package.json index 3516477f1..51e620d33 100644 --- a/vitest-accessibility-checker/package.json +++ b/vitest-accessibility-checker/package.json @@ -40,7 +40,6 @@ "@vitest/browser": "^4.1.6", "@vitest/browser-playwright": "^4.1.6", "@vitest/ui": "^4.1.6", - "adm-zip": "^0.5.18", "eslint": "^8.4.1", "http-server": "^14.1.1", "playwright": "^1.40.0", @@ -51,6 +50,7 @@ }, "dependencies": { "@ibm/telemetry-js": "^1.9.1", + "adm-zip": "^0.5.18", "axios": "^1.7.9", "js-yaml": "^4.2.0", "microdiff": "^1.5.0", diff --git a/vitest-accessibility-checker/src/package-lock.json b/vitest-accessibility-checker/src/package-lock.json index 4288c9ef8..8735400d6 100644 --- a/vitest-accessibility-checker/src/package-lock.json +++ b/vitest-accessibility-checker/src/package-lock.json @@ -13,16 +13,11 @@ "@ibm/telemetry-js": "^1.9.1", "axios": "^1.7.9", "js-yaml": "^4.2.0", - "microdiff": "^1.5.0" - }, - "peerDependencies": { - "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", + "microdiff": "^1.5.0", "write-excel-file": "^4.1.1" }, - "peerDependenciesMeta": { - "write-excel-file": { - "optional": true - } + "peerDependencies": { + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0" } }, "node_modules/@ibm/telemetry-js": { @@ -686,6 +681,12 @@ } } }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT" + }, "node_modules/follow-redirects": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", @@ -1573,6 +1574,18 @@ "engines": { "node": ">=8" } + }, + "node_modules/write-excel-file": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/write-excel-file/-/write-excel-file-4.1.1.tgz", + "integrity": "sha512-MUnCnNtQrcZek832ZcU24uU0rSphFmKPD1DvIjXOlygVb93CV7Tme6H3jUTkxsMmjB2W7HIzERzjqTi5kui71A==", + "license": "MIT", + "dependencies": { + "fflate": "^0.8.2" + }, + "engines": { + "node": ">=18" + } } } }