diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 53265643..ca29e15c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -28,8 +28,8 @@ Steps to reproduce the behavior: ### Environment -- Cast Kodi version: -- Browser version: +- Cast Kodi version: +- Browser version: - Kodi version: - Kodi add-on version (if appropriate): diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 599c8849..8bd28278 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -17,8 +17,8 @@ assignees: "" ### Environment -- Cast Kodi version: -- Browser version: +- Cast Kodi version: +- Browser version: - Kodi version: - Kodi add-on version (if appropriate): diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de831c91..65274b0a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,9 +82,9 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: javascript - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.metalint/eslint.config.js b/.metalint/eslint.config.js index cfb77409..42dbb36b 100644 --- a/.metalint/eslint.config.js +++ b/.metalint/eslint.config.js @@ -704,6 +704,7 @@ export default { { checkGlobalVariables: true }, ], "unicorn/no-unnecessary-await": "error", + "unicorn/no-unnecessary-polyfills": "error", "unicorn/no-unreadable-array-destructuring": "error", "unicorn/no-unreadable-iife": "error", "unicorn/no-unused-properties": "error", diff --git a/.metalint/markdownlint.config.js b/.metalint/markdownlint.config.js index ebaf1d6d..682ce125 100644 --- a/.metalint/markdownlint.config.js +++ b/.metalint/markdownlint.config.js @@ -72,4 +72,6 @@ export default { "link-image-reference-definitions": true, // eslint-disable-next-line camelcase "link-image-style": { shortcut: false, url_inline: false }, + "table-pipe-style": { style: "leading_and_trailing" }, + "table-column-count": true, }; diff --git a/.metalint/stylelint.config.js b/.metalint/stylelint.config.js index 5beea9cb..ea2d45cd 100644 --- a/.metalint/stylelint.config.js +++ b/.metalint/stylelint.config.js @@ -188,6 +188,7 @@ export default { "hue-degree-notation": "angle", "import-notation": "string", "keyframe-selector-notation": "keyword", + "lightness-notation": "percentage", "media-feature-range-notation": "context", "selector-not-notation": "complex", "selector-pseudo-element-colon-notation": "double", diff --git a/LICENSE b/LICENSE index 99244dd9..7199dfab 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017-2023 Sébastien Règne +Copyright (c) 2017-2024 Sébastien Règne Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index aceaf900..594d9260 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,10 @@ dans la page _Paramètres_ / _Infos sur le système_ / _Résumé_. ## Contribuer [Node.js et -npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/) sont +npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) sont nécessaires pour contribuer au projet. Après avoir [forké et -cloné](https://docs.github.com/get-started/quickstart/fork-a-repo) Cast Kodi, -exécutez `npm ci` pour télécharger les dépendances. Voici d'autres +cloné](https://docs.github.com/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) +Cast Kodi, exécutez `npm ci` pour télécharger les dépendances. Voici d'autres commandes utiles : - `npm run lint` : faire une analyse statique des fichiers ; diff --git a/asset/banner_920x680.svg b/asset/banner_920x680.svg deleted file mode 100644 index c75fb9d4..00000000 --- a/asset/banner_920x680.svg +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cast Kodi - diff --git a/package-lock.json b/package-lock.json index 2acc0b58..83030c60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,44 +10,44 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "linkedom": "0.16.4" + "linkedom": "0.16.8" }, "devDependencies": { "@prantlf/jsonlint": "14.0.3", "@prettier/plugin-xml": "3.2.2", - "@stryker-mutator/core": "8.0.0", - "@stryker-mutator/mocha-runner": "8.0.0", + "@stryker-mutator/core": "8.2.2", + "@stryker-mutator/mocha-runner": "8.2.2", "@types/firefox-webext-browser": "120.0.0", "@types/jsdom": "21.1.6", "@types/mocha": "10.0.6", - "@types/sinon": "17.0.2", - "addons-linter": "6.19.0", - "eslint": "8.55.0", + "@types/sinon": "17.0.3", + "addons-linter": "6.21.0", + "eslint": "8.56.0", "eslint-plugin-array-func": "4.0.0", "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-import": "2.29.0", - "eslint-plugin-jsdoc": "46.9.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsdoc": "48.0.4", "eslint-plugin-mocha": "10.2.0", - "eslint-plugin-n": "16.3.1", + "eslint-plugin-n": "16.6.2", "eslint-plugin-no-unsanitized": "4.0.2", "eslint-plugin-promise": "6.1.1", - "eslint-plugin-regexp": "2.1.2", - "eslint-plugin-unicorn": "49.0.0", + "eslint-plugin-regexp": "2.2.0", + "eslint-plugin-unicorn": "50.0.1", "htmlhint": "1.1.4", - "jsdom": "23.0.1", - "markdownlint": "0.32.1", - "metalint": "0.14.1", + "jsdom": "24.0.0", + "markdownlint": "0.33.0", + "metalint": "0.15.0", "mocha": "10.2.0", "mock-socket": "9.3.1", "npm-package-json-lint": "7.1.0", - "prettier": "3.1.0", + "prettier": "3.2.4", "purgecss": "5.0.0", "sinon": "17.0.1", - "stylelint": "16.0.1", + "stylelint": "16.2.0", "stylelint-order": "6.0.4", - "typedoc": "0.25.4", + "typedoc": "0.25.7", "typescript": "5.3.3", - "web-ext": "7.9.0", + "web-ext": "7.11.0", "yaml-lint": "1.7.0" }, "engines": { @@ -173,21 +173,21 @@ } }, "node_modules/@babel/core": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", - "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", - "@babel/helper-compilation-targets": "^7.22.15", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.5", - "@babel/parser": "^7.23.5", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -212,12 +212,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", - "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.5", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -239,14 +239,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -264,9 +264,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz", - "integrity": "sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.9.tgz", + "integrity": "sha512-B2L9neXTIyPQoXDm+NtovPvG6VOLWnaXu3BIeVDWwdKFgG30oNa6CqVGiJPDWQwIAK49t9gnQI9c6K6RzabiKw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -474,14 +474,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", - "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5" + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -573,9 +573,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", - "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -585,15 +585,13 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.5.tgz", - "integrity": "sha512-6IsY8jOeWibsengGlWIezp7cuZEFzNlAghFpzh9wiZwhQ42/hRcPnY/QV9HJoKTlujupinSlnQPiEy/u2C1ZfQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.9.tgz", + "integrity": "sha512-hJhBCb0+NnTWybvWq2WpbCYDOcflSbx0t+BYP65e5R9GVnukiDTi+on5bFkk4p7QGuv190H6KfNiV9Knf/3cZA==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.23.5", + "@babel/helper-create-class-features-plugin": "^7.23.9", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-split-export-declaration": "^7.22.6", "@babel/plugin-syntax-decorators": "^7.23.3" }, "engines": { @@ -666,13 +664,13 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.5.tgz", - "integrity": "sha512-2fMkXEJkrmwgu2Bsv1Saxgj30IXZdJ+84lQcKKI7sm719oXs0BBw2ZENKdJdR1PjWndgLCEBNXJOri0fk7RYQA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", + "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.23.5", + "@babel/helper-create-class-features-plugin": "^7.23.6", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-typescript": "^7.23.3" }, @@ -715,34 +713,34 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", - "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", + "@babel/generator": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.5", - "@babel/types": "^7.23.5", - "debug": "^4.1.0", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -750,9 +748,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", - "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -764,9 +762,9 @@ } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.2.tgz", - "integrity": "sha512-sLYGdAdEY2x7TSw9FtmdaTrh2wFtRJO5VMbBrA8tEqEod7GEggFmxTSK9XqExib3yMuYNcvcTdCZIP6ukdjAIA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.5.0.tgz", + "integrity": "sha512-abypo6m9re3clXA00eu5syw+oaPHbJTPapu9C4pzNsJ4hdZDzushT50Zhu+iIYXgEe1CxnRMn7ngsbV+MLrlpQ==", "dev": true, "funding": [ { @@ -782,13 +780,13 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.2.1" + "@csstools/css-tokenizer": "^2.2.3" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.1.tgz", - "integrity": "sha512-Zmsf2f/CaEPWEVgw29odOj+WEVoiJy9s9NOv5GgNY9mZ1CZ7394By6wONrONrTsnNDv6F9hR02nvFihrGVGHBg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.3.tgz", + "integrity": "sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg==", "dev": true, "funding": [ { @@ -805,9 +803,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.5.tgz", - "integrity": "sha512-IxVBdYzR8pYe89JiyXQuYk4aVVoCPhMJkz6ElRwlVysjwURTsTk/bmY/z4FfeRE+CRBMlykPwXEVUg8lThv7AQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.7.tgz", + "integrity": "sha512-lHPKJDkPUECsyAvD60joYfDmp8UERYxHGkFfyLJFTVK/ERJe0sVlIFLXU5XFxdjNDTerp5L4KeaKG+Z5S94qxQ==", "dev": true, "funding": [ { @@ -823,14 +821,14 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.3.2", - "@csstools/css-tokenizer": "^2.2.1" + "@csstools/css-parser-algorithms": "^2.5.0", + "@csstools/css-tokenizer": "^2.2.3" } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz", - "integrity": "sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.1.tgz", + "integrity": "sha512-NPljRHkq4a14YzZ3YD406uaxh7s0g6eAq3L9aLOWywoqe8PkYamAvtsh7KNX6c++ihDrJ0RiU+/z7rGnhlZ5ww==", "dev": true, "funding": [ { @@ -985,9 +983,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1030,9 +1028,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1238,9 +1236,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1248,21 +1246,21 @@ } }, "node_modules/@ljharb/through": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", - "integrity": "sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==", + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", + "integrity": "sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.5" }, "engines": { "node": ">= 0.4" } }, "node_modules/@mdn/browser-compat-data": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.4.3.tgz", - "integrity": "sha512-+VnaO5zYUwFQVuRqp2qLPGR5GwhhJ/lrp0yEmamJ/nI15P2GKwGBEWRDiITZR8i6AYxeiQSu2rOi/gqxehnPuA==", + "version": "5.5.7", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.7.tgz", + "integrity": "sha512-DoHTZ/TjtNfUu9eiqJd+x3IcCQrhS+yOYU436TKUnlE36jZwNbK535D1CmTsSYdi/UcdCWNm5KRQZ9g1tlZCPw==", "dev": true }, "node_modules/@nodelib/fs.scandir": { @@ -1439,14 +1437,14 @@ "dev": true }, "node_modules/@stryker-mutator/api": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/api/-/api-8.0.0.tgz", - "integrity": "sha512-4R8yieczpgOrOBQYq1d1aRJLcgenltpMH9ugtIYPPVmENFUo+mWm9HmaahLe+TVHnJSb4OZ4lvI7dVIhoBaiSQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@stryker-mutator/api/-/api-8.2.2.tgz", + "integrity": "sha512-+oKJod6GfJ/jHKxF0eH199NKuTSkMna/d4EZipqgsdLBelH+/nkJqpfyvFjZx13N+ksN9IaJNQ3TJHfsxiSauA==", "dev": true, "dependencies": { - "mutation-testing-metrics": "3.0.0", - "mutation-testing-report-schema": "3.0.0", - "tslib": "~2.6.0", + "mutation-testing-metrics": "3.0.2", + "mutation-testing-report-schema": "3.0.2", + "tslib": "~2.6.2", "typed-inject": "~4.0.0" }, "engines": { @@ -1454,39 +1452,39 @@ } }, "node_modules/@stryker-mutator/core": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/core/-/core-8.0.0.tgz", - "integrity": "sha512-dyPs60wtLS9vgghgL5a49k/7KOovOnavXzm5SIBBsBJuxoO+5rvGXRohZaqSoZdb0yWIvp+LFdu6qWcdlJPkoQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@stryker-mutator/core/-/core-8.2.2.tgz", + "integrity": "sha512-1FO1G3Rp+Y2V8ad1yQFzCucxZlfMi2STAwIblmQDURoiZUcT6ZCa4t9hvs7hW/tM9vnpPbx7OnGJh2WlIiKKwQ==", "dev": true, "dependencies": { - "@stryker-mutator/api": "8.0.0", - "@stryker-mutator/instrumenter": "8.0.0", - "@stryker-mutator/util": "8.0.0", + "@stryker-mutator/api": "8.2.2", + "@stryker-mutator/instrumenter": "8.2.2", + "@stryker-mutator/util": "8.2.2", "ajv": "~8.12.0", "chalk": "~5.3.0", "commander": "~11.1.0", "diff-match-patch": "1.0.5", "emoji-regex": "~10.3.0", - "execa": "~8.0.0", + "execa": "~8.0.1", "file-url": "~4.0.0", "get-port": "~7.0.0", - "glob": "~10.3.0", - "inquirer": "~9.2.0", + "glob": "~10.3.10", + "inquirer": "~9.2.13", "lodash.groupby": "~4.6.0", - "log4js": "~6.9.0", - "minimatch": "~9.0.1", - "mutation-testing-elements": "3.0.1", - "mutation-testing-metrics": "3.0.0", - "mutation-testing-report-schema": "3.0.0", - "npm-run-path": "~5.1.0", - "progress": "~2.0.0", - "rxjs": "~7.8.0", - "semver": "^7.3.5", - "source-map": "~0.7.3", + "log4js": "~6.9.1", + "minimatch": "~9.0.3", + "mutation-testing-elements": "3.0.2", + "mutation-testing-metrics": "3.0.2", + "mutation-testing-report-schema": "3.0.2", + "npm-run-path": "~5.2.0", + "progress": "~2.0.3", + "rxjs": "~7.8.1", + "semver": "^7.5.4", + "source-map": "~0.7.4", "tree-kill": "~1.2.2", "tslib": "2.6.2", "typed-inject": "~4.0.0", - "typed-rest-client": "~1.8.0" + "typed-rest-client": "~1.8.11" }, "bin": { "stryker": "bin/stryker.js" @@ -1496,48 +1494,48 @@ } }, "node_modules/@stryker-mutator/instrumenter": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/instrumenter/-/instrumenter-8.0.0.tgz", - "integrity": "sha512-kS3BdpqDuJeRBDBw2eP68rhUrgtlT5EGERNOwCwUGpfTtUan7y2zX9ZGEblOtMI5yTtyBArFZMtwhPGi+waJ/Q==", - "dev": true, - "dependencies": { - "@babel/core": "~7.23.0", - "@babel/generator": "~7.23.0", - "@babel/parser": "~7.23.0", - "@babel/plugin-proposal-decorators": "~7.23.0", - "@babel/preset-typescript": "~7.23.0", - "@stryker-mutator/api": "8.0.0", - "@stryker-mutator/util": "8.0.0", - "angular-html-parser": "~5.0.0", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@stryker-mutator/instrumenter/-/instrumenter-8.2.2.tgz", + "integrity": "sha512-kR8v2SdlnZAN4Jh26t1PmunPy2FXtNuML2O6Z91qPrpLrUNMKSt5xzSWEZSsleGpXqS4iJ1YVE45Fex5OelySw==", + "dev": true, + "dependencies": { + "@babel/core": "~7.23.9", + "@babel/generator": "~7.23.6", + "@babel/parser": "~7.23.9", + "@babel/plugin-proposal-decorators": "~7.23.9", + "@babel/preset-typescript": "~7.23.3", + "@stryker-mutator/api": "8.2.2", + "@stryker-mutator/util": "8.2.2", + "angular-html-parser": "~5.2.0", "semver": "~7.5.4", - "weapon-regex": "~1.1.0" + "weapon-regex": "~1.3.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@stryker-mutator/mocha-runner": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/mocha-runner/-/mocha-runner-8.0.0.tgz", - "integrity": "sha512-23qNT78l68d/OBrq64UDCKBoYDc+PMbmvTTYrQcCDRKaRn97wEG44ADR+ebqxdEUnV1iiqUXkVMki3jRuYk8gw==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@stryker-mutator/mocha-runner/-/mocha-runner-8.2.2.tgz", + "integrity": "sha512-UjT1CLrwPl2C+eZS4kU2RIfXtGHuzNoC8d1W1/fGx8qu9m0XXuXiG6/nW3q3DczVA8oePiKMGTzbfM9/U10kFA==", "dev": true, "dependencies": { - "@stryker-mutator/api": "8.0.0", - "@stryker-mutator/util": "8.0.0", - "tslib": "~2.6.0" + "@stryker-mutator/api": "8.2.2", + "@stryker-mutator/util": "8.2.2", + "tslib": "~2.6.2" }, "engines": { "node": ">=18.0.0" }, "peerDependencies": { - "@stryker-mutator/core": "~8.0.0", + "@stryker-mutator/core": "~8.2.0", "mocha": ">= 7.2 < 11" } }, "node_modules/@stryker-mutator/util": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/util/-/util-8.0.0.tgz", - "integrity": "sha512-geb2JvbYXDs6vOjGV9514PK+L6NiYFQIYhkpKvzfZQWYijNYnLhxXKz/X264a9StTYbGb/ZBADOkzsVde/5zig==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@stryker-mutator/util/-/util-8.2.2.tgz", + "integrity": "sha512-dSB/3heMHJ4AdwYl3G9gP0gXvYA4fAFVb1KYRK3xiOuyNsVB1MaFHlw7ulNF/eW5tiEHUzOMuhWWHAbwYwVR7A==", "dev": true }, "node_modules/@szmarczak/http-timer": { @@ -1600,9 +1598,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", - "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "version": "20.10.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz", + "integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1615,9 +1613,9 @@ "dev": true }, "node_modules/@types/sinon": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.2.tgz", - "integrity": "sha512-Zt6heIGsdqERkxctIpvN5Pv3edgBrhoeb3yHyxffd4InN0AX2SVNKSrhdDZKGQICVOxWP/q4DyhpfPNMSrpIiA==", + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", "dev": true, "dependencies": { "@types/sinonjs__fake-timers": "*" @@ -1672,9 +1670,9 @@ } }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1693,35 +1691,35 @@ } }, "node_modules/addons-linter": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-6.19.0.tgz", - "integrity": "sha512-Yz5YRfIQ12dIqXKmEoHNwoS/L1xIve2hdm9UEesOEsov5W0zeWMOWCnqdvJNVNy7f1FnPu1lnqzylelkTBS7dA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-6.21.0.tgz", + "integrity": "sha512-4GBn14BR16FZE7dog6uz+1HO6V3B+mAVxmbwxRhed2y5eyrwIW832TmEpku+5A5bbovBZ4gilXEtBsl6A1AMmg==", "dev": true, "dependencies": { "@fluent/syntax": "0.19.0", - "@mdn/browser-compat-data": "5.4.3", + "@mdn/browser-compat-data": "5.5.7", "addons-moz-compare": "1.3.0", - "addons-scanner-utils": "9.8.0", + "addons-scanner-utils": "9.9.0", "ajv": "8.12.0", "chalk": "4.1.2", "cheerio": "1.0.0-rc.12", "columnify": "1.6.0", "common-tags": "1.8.2", "deepmerge": "4.3.1", - "eslint": "8.55.0", + "eslint": "8.56.0", "eslint-plugin-no-unsanitized": "4.0.2", "eslint-visitor-keys": "3.4.3", "espree": "9.6.1", "esprima": "4.0.1", "fast-json-patch": "3.1.1", "glob": "10.3.10", - "image-size": "1.0.2", + "image-size": "1.1.1", "is-mergeable-object": "1.1.1", "jed": "1.1.1", "json-merge-patch": "1.0.2", "os-locale": "5.0.0", - "pino": "8.16.2", - "postcss": "8.4.32", + "pino": "8.17.2", + "postcss": "8.4.33", "relaxed-json": "1.0.3", "semver": "7.5.4", "sha.js": "2.4.11", @@ -1773,9 +1771,9 @@ "dev": true }, "node_modules/addons-scanner-utils": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-9.8.0.tgz", - "integrity": "sha512-nJJ4QazrtMImyb2OK9SGZlNtinNu25dzOR0lhWthhJQN2iDOf3yqHdSiVBEeZvCwuT/sS1cU6me4O4kgEATjFQ==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-9.9.0.tgz", + "integrity": "sha512-YDP10U3sEZMuIgnjXMiAYgUU64jTbxmhpUXMlhi1nKO4Etz+ctGWoTUst7IQRoLWaY9y2r1KZDG3jALxLA1n7Q==", "dev": true, "dependencies": { "@types/yauzl": "2.10.3", @@ -1867,9 +1865,9 @@ } }, "node_modules/angular-html-parser": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/angular-html-parser/-/angular-html-parser-5.0.2.tgz", - "integrity": "sha512-fov2PwgZDgDsvZXPRa0+lbJyakOZOlFb5eiACR2i6RSn9ad5A+84/SwVfj/dUCbUAHH1ta2uvaoAKEijG93Sfg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/angular-html-parser/-/angular-html-parser-5.2.0.tgz", + "integrity": "sha512-8S/8g5iMcuGhRmBUJ+xuXm9hdjqIcaky2z52RA7tSyz9tWN0mgiP/JR9+kx/SiS1REJpTXnEKpMCMEeVVIeo3A==", "dev": true, "dependencies": { "tslib": "^2.6.2" @@ -2620,9 +2618,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001566", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", - "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "version": "1.0.30001576", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", + "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", "dev": true, "funding": [ { @@ -2768,9 +2766,9 @@ } }, "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", + "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", "dev": true, "funding": [ { @@ -3091,6 +3089,19 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-js-compat": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", + "integrity": "sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -3222,15 +3233,15 @@ "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" }, "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", "dev": true, "dependencies": { "rrweb-cssom": "^0.6.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/dashdash": { @@ -3614,9 +3625,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.609", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.609.tgz", - "integrity": "sha512-ihiCP7PJmjoGNuLpl7TjNA8pCQWu09vGyjlPYw1Rqww4gvNuCcmvl+44G+2QyJ6S2K4o+wbTS++Xz0YN8Q9ERw==", + "version": "1.4.626", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.626.tgz", + "integrity": "sha512-f7/be56VjRRQk+Ric6PmIrEtPcIqsn3tElyAu9Sh6egha2VLJ82qwkcOdcnT06W+Pb6RUulV1ckzrGbKzVcTHg==", "dev": true }, "node_modules/emoji-regex": { @@ -3805,15 +3816,15 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", + "@eslint/js": "8.56.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3978,9 +3989,9 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", - "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { "array-includes": "^3.1.7", @@ -3999,7 +4010,7 @@ "object.groupby": "^1.0.1", "object.values": "^1.1.7", "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -4061,9 +4072,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "46.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.9.0.tgz", - "integrity": "sha512-UQuEtbqLNkPf5Nr/6PPRCtr9xypXY+g8y/Q7gPa0YK7eDhh0y2lWprXRnaYbW7ACgIUvpDKy9X2bZqxtGzBG9Q==", + "version": "48.0.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.0.4.tgz", + "integrity": "sha512-A0cH+5svWPXzGZszBjXA1t0aAqVGS+/x3i02KFmb73rU0iMLnadEcVWcD/dGBZHIfAMKr3YpWh58f6wn4N909w==", "dev": true, "dependencies": { "@es-joy/jsdoccomment": "~0.41.0", @@ -4074,13 +4085,13 @@ "esquery": "^1.5.0", "is-builtin-module": "^3.2.1", "semver": "^7.5.4", - "spdx-expression-parse": "^3.0.1" + "spdx-expression-parse": "^4.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-plugin-mocha": { @@ -4100,15 +4111,16 @@ } }, "node_modules/eslint-plugin-n": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.3.1.tgz", - "integrity": "sha512-w46eDIkxQ2FaTHcey7G40eD+FhTXOdKudDXPUO2n9WNcslze/i/HT2qJ3GXjHngYSGDISIgPNhwGtgoix4zeOw==", + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.1.0", + "eslint-plugin-es-x": "^7.5.0", "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", "ignore": "^5.2.4", "is-builtin-module": "^3.2.1", "is-core-module": "^2.12.1", @@ -4136,6 +4148,21 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-plugin-n/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4148,6 +4175,18 @@ "node": "*" } }, + "node_modules/eslint-plugin-n/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-plugin-no-unsanitized": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.2.tgz", @@ -4170,9 +4209,9 @@ } }, "node_modules/eslint-plugin-regexp": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.1.2.tgz", - "integrity": "sha512-nnhNqHblaD8YTJiEHfyVRhiw8sm0eFQ9h+ee3rMqJhf2R9sJWbSXkjrLxIeCNZSNqitUOdaYFfrPVyvS9i72AA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.2.0.tgz", + "integrity": "sha512-0kwpiWiLRVBkVr3oIRQLl196sXP/NF6DQFefv9jtR4ZOgQR+6WID2pIZ0I+wIt54qgBPwBB7Gm2a+ueh8/WsFQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -4191,15 +4230,17 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "49.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-49.0.0.tgz", - "integrity": "sha512-0fHEa/8Pih5cmzFW5L7xMEfUTvI9WKeQtjmKpTUmY+BiFCDxkxrTdnURJOHKykhtwIeyYsxnecbGvDCml++z4Q==", + "version": "50.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-50.0.1.tgz", + "integrity": "sha512-KxenCZxqSYW0GWHH18okDlOQcpezcitm5aOSz6EnobyJ6BIByiPDviQRjJIUAjG/tMN11958MxaQ+qCoU6lfDA==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "@eslint-community/eslint-utils": "^4.4.0", - "ci-info": "^3.8.0", + "@eslint/eslintrc": "^2.1.4", + "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", + "core-js-compat": "^3.34.0", "esquery": "^1.5.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.1", @@ -4218,7 +4259,7 @@ "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=8.52.0" + "eslint": ">=8.56.0" } }, "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { @@ -4331,9 +4372,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4600,9 +4641,9 @@ } }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -4641,31 +4682,27 @@ } }, "node_modules/figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=14" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/figures/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, "node_modules/file-entry-cache": { @@ -4968,9 +5005,9 @@ } }, "node_modules/fx-runner": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.3.0.tgz", - "integrity": "sha512-5b37H4GCyhF+Nf8xk9mylXoDq4wb7pbGAXxlCXp/631UTeeZomWSYcEGXumY4wk8g2QAqjPMGdWW+RbNt8PUcA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.4.0.tgz", + "integrity": "sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg==", "dev": true, "dependencies": { "commander": "2.9.0", @@ -5798,9 +5835,9 @@ } }, "node_modules/image-size": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", - "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", "dev": true, "dependencies": { "queue": "6.0.2" @@ -5809,7 +5846,7 @@ "image-size": "bin/image-size.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.x" } }, "node_modules/immediate": { @@ -5884,18 +5921,18 @@ "dev": true }, "node_modules/inquirer": { - "version": "9.2.12", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.12.tgz", - "integrity": "sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==", + "version": "9.2.13", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.13.tgz", + "integrity": "sha512-mUlJNemjYioZgaZXqEFlQ0z9GD8/o+pavIF3JyhzWLX4Xa9M1wioGMCxQEFmps70un9lrah2WaBl3kSRVcoV3g==", "dev": true, "dependencies": { - "@ljharb/through": "^2.3.11", + "@ljharb/through": "^2.3.12", "ansi-escapes": "^4.3.2", "chalk": "^5.3.0", "cli-cursor": "^3.1.0", "cli-width": "^4.1.0", "external-editor": "^3.1.0", - "figures": "^5.0.0", + "figures": "^3.2.0", "lodash": "^4.17.21", "mute-stream": "1.0.0", "ora": "^5.4.1", @@ -6055,6 +6092,21 @@ "is-ci": "bin.js" } }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", @@ -6352,12 +6404,12 @@ "dev": true }, "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6487,12 +6539,12 @@ } }, "node_modules/jsdom": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.1.tgz", - "integrity": "sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==", + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz", + "integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==", "dev": true, "dependencies": { - "cssstyle": "^3.0.0", + "cssstyle": "^4.0.1", "data-urls": "^5.0.0", "decimal.js": "^10.4.3", "form-data": "^4.0.0", @@ -6511,7 +6563,7 @@ "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", - "ws": "^8.14.2", + "ws": "^8.16.0", "xml-name-validator": "^5.0.0" }, "engines": { @@ -6690,9 +6742,9 @@ } }, "node_modules/just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", "dev": true }, "node_modules/jwa": { @@ -6821,9 +6873,9 @@ "dev": true }, "node_modules/linkedom": { - "version": "0.16.4", - "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.16.4.tgz", - "integrity": "sha512-SykvDVh/jAnaO+WiPqH5vX3QpZrIRImuppzYhIHons3RXPhDwqN2dOyfopOVaHleqWtoS+3vWCqen+m8M3HToQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.16.8.tgz", + "integrity": "sha512-+HtHVHBb3yZKlP9pgcJdi1AIG9tsAuo+Qtlz+79cCTsxgQwDzajsZjYvpp+DEckCK/zoGVhzkADniYZQ57KcFQ==", "dependencies": { "css-select": "^5.1.0", "cssom": "^0.5.0", @@ -6833,9 +6885,9 @@ } }, "node_modules/linkedom/node_modules/htmlparser2": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.0.0.tgz", - "integrity": "sha512-uxbSI98wmFT/G4P2zXx4OVx04qWUmyFPrD2/CNepa2Zo3GPNaCaaxElDgwUrwYWkK1nr9fft0Ya8dws8coDLLQ==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -6851,12 +6903,12 @@ } }, "node_modules/linkify-it": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", - "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, "dependencies": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "node_modules/locate-path": { @@ -6936,18 +6988,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-symbols/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7034,41 +7074,30 @@ } }, "node_modules/markdown-it": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", - "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.0.0.tgz", + "integrity": "sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==", "dev": true, "dependencies": { "argparse": "^2.0.1", - "entities": "~3.0.1", - "linkify-it": "^4.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.0.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/markdownlint": { - "version": "0.32.1", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.32.1.tgz", - "integrity": "sha512-3sx9xpi4xlHlokGyHO9k0g3gJbNY4DI6oNEeEYq5gQ4W7UkiJ90VDAnuDl2U+yyXOUa6BX+0gf69ZlTUGIBp6A==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.33.0.tgz", + "integrity": "sha512-4lbtT14A3m0LPX1WS/3d1m7Blg+ZwiLq36WvjQqFGsX3Gik99NV+VXp/PW3n+Q62xyPdbvGOCfjPqjW+/SKMig==", "dev": true, "dependencies": { - "markdown-it": "13.0.2", - "markdownlint-micromark": "0.1.7" + "markdown-it": "14.0.0", + "markdownlint-micromark": "0.1.8" }, "engines": { "node": ">=18" @@ -7078,12 +7107,15 @@ } }, "node_modules/markdownlint-micromark": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz", - "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.8.tgz", + "integrity": "sha512-1ouYkMRo9/6gou9gObuMDnvZM8jC/ly3QCFQyoSPCS2XV1ZClU0xpKbL1Ar3bWWRT1RnBZkWUEiNKrI2CwiBQA==", "dev": true, "engines": { "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" } }, "node_modules/marked": { @@ -7121,9 +7153,9 @@ "dev": true }, "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "dev": true }, "node_modules/mem": { @@ -7203,9 +7235,9 @@ } }, "node_modules/metalint": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/metalint/-/metalint-0.14.1.tgz", - "integrity": "sha512-lQDYpfmhsLuMFJhBrlacyML0iQaRFitjl3kecUzly7X7M49UMuOZGV4bNTqMMTYEN8wtUPvEitjZEkXzgVejlQ==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/metalint/-/metalint-0.15.0.tgz", + "integrity": "sha512-U4RTfBedIIP1gJp+BLyg+gkwqfRLTFFi9El/2tkKqBgi5dLlUr9FFrj47JrTHNBqSru7DuJYth+PZS/g6zIoRA==", "dev": true, "dependencies": { "chalk": "5.3.0", @@ -7215,7 +7247,7 @@ "metalint": "src/bin/index.js" }, "engines": { - "node": ">=20.0.0" + "node": ">=20.6.0" }, "funding": { "url": "https://www.paypal.me/sebastienregne" @@ -7521,9 +7553,9 @@ } }, "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "dev": true, "optional": true, "engines": { @@ -7589,24 +7621,24 @@ } }, "node_modules/mutation-testing-elements": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mutation-testing-elements/-/mutation-testing-elements-3.0.1.tgz", - "integrity": "sha512-hsBKkabjD2sjyR2vhdEFPDxZfYLw71geIWjEh4rcZSSQAtyWRfjGf6UbdMjleuyw1ZZTgGt6CImtwRY7s3lrVg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mutation-testing-elements/-/mutation-testing-elements-3.0.2.tgz", + "integrity": "sha512-ISsvj+2pfcyAUEMig83Y5KFvWpy3wJ3NIcXiJ6hD5NQeDdZJnhagRJqLQTwBRkzblqiAuYpY611v4isYJauBbg==", "dev": true }, "node_modules/mutation-testing-metrics": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-3.0.0.tgz", - "integrity": "sha512-WslGuCdpqT+6SpeIahMhLrJl5+YbutlOCFKxuULIkAkaHfsWBK8UCq6euE7PiDEx+R1pYZo//kqRbFIOFmdQug==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-3.0.2.tgz", + "integrity": "sha512-FpyCAz43Mmq/l7BIyBrZLv8z3kc5XHNei/DcAyEVSXyj2i+h4jLhen4SiW/BPMijCIMVyiOeMJPMIfaYxrFZGg==", "dev": true, "dependencies": { - "mutation-testing-report-schema": "3.0.0" + "mutation-testing-report-schema": "3.0.2" } }, "node_modules/mutation-testing-report-schema": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-3.0.0.tgz", - "integrity": "sha512-70+ZPYoyedruSGiEcXQnFiTtIusBYlsL/2EMwfR+/HOqBGxBpmI798spqc86ZVYXPVCL5mt2rWjE1dTQwcjpmQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-3.0.2.tgz", + "integrity": "sha512-1F6s37zFDsoWa262sANVBDKANMvmKPVU1FAVEpSCMtKAGkFoar+tjXUlPnD0dWJfPuKV58G86zP7sMlcu+QOJQ==", "dev": true }, "node_modules/mute-stream": { @@ -7817,43 +7849,16 @@ } }, "node_modules/nise": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", - "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "node_modules/nise/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.7.tgz", + "integrity": "sha512-wWtNUhkT7k58uvWTB/Gy26eA/EJKtPZFVAhEilN5UYVmmGRYOURbejRUyKm0Uu9XVEW7K5nBOZfR8VMB4QR2RQ==", "dev": true, "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/nise/node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/text-encoding": "^0.7.2", + "just-extend": "^6.2.0", + "path-to-regexp": "^6.2.1" } }, "node_modules/node-domexception": { @@ -8091,9 +8096,9 @@ } }, "node_modules/npm-package-json-lint/node_modules/type-fest": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.3.tgz", - "integrity": "sha512-//BaTm14Q/gHBn09xlnKNqfI8t6bmdzx2DXYfPBNofN0WUybCEUDcbCWcTa0oF09lzLjZgPphXAsvRiMK0V6Bw==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.9.0.tgz", + "integrity": "sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==", "dev": true, "engines": { "node": ">=16" @@ -8103,9 +8108,9 @@ } }, "node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -8352,18 +8357,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ora/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ora/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8725,18 +8718,9 @@ } }, "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-to-regexp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", "dev": true }, "node_modules/path-type": { @@ -8779,9 +8763,9 @@ } }, "node_modules/pino": { - "version": "8.16.2", - "resolved": "https://registry.npmjs.org/pino/-/pino-8.16.2.tgz", - "integrity": "sha512-2advCDGVEvkKu9TTVSa/kWW7Z3htI/sBKEZpqiHk6ive0i/7f5b1rsU8jn0aimxqfnSz5bj/nOYkwhBUn5xxvg==", + "version": "8.17.2", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.17.2.tgz", + "integrity": "sha512-LA6qKgeDMLr2ux2y/YiUt47EfgQ+S9LznBWOJdN3q1dx2sv0ziDLUBeVpyVv17TEcGCBuWf0zNtg3M5m1NhhWQ==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0", @@ -8789,7 +8773,7 @@ "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "v1.1.0", "pino-std-serializers": "^6.0.0", - "process-warning": "^2.0.0", + "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", @@ -8835,9 +8819,9 @@ } }, "node_modules/pino-abstract-transport/node_modules/readable-stream": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz", - "integrity": "sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, "dependencies": { "abort-controller": "^3.0.0", @@ -8881,9 +8865,9 @@ } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "dev": true, "funding": [ { @@ -8941,9 +8925,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -8996,9 +8980,9 @@ } }, "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", + "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -9026,9 +9010,9 @@ "dev": true }, "node_modules/process-warning": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.3.2.tgz", - "integrity": "sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", "dev": true }, "node_modules/progress": { @@ -9083,6 +9067,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pupa": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", @@ -10005,15 +9998,18 @@ "optional": true }, "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.1.tgz", + "integrity": "sha512-Y5NejJTTliTyY4H7sipGqY+RX5P87i3F7c4Rcepy72nq+mNLhIsD0W4c7kEmduMDQCSqtPsXPlSTsFhh2LQv+g==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", "is-regex": "^1.1.4" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10210,9 +10206,9 @@ "dev": true }, "node_modules/shiki": { - "version": "0.14.6", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.6.tgz", - "integrity": "sha512-R4koBBlQP33cC8cpzX0hAoOURBHJILp4Aaduh2eYi+Vj8ZBqtK/5SWNEHBS3qwUMu8dqOtI/ftno3ESfNeVW9g==", + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", + "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", "dev": true, "dependencies": { "ansi-sequence-parser": "^1.1.0", @@ -10239,6 +10235,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-5.3.0.tgz", "integrity": "sha512-7nHlCzhQgVMLBNiXVEgbG/raq48awOW0lYMN5uo1BaB3mp0+k8M8pvDwbfTlr3apcxZJsk9HQsAW1POwoJugpQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { "common-tags": "1.8.2", @@ -10322,9 +10319,9 @@ } }, "node_modules/sonic-boom": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.7.0.tgz", - "integrity": "sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz", + "integrity": "sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0" @@ -10388,6 +10385,16 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -10395,9 +10402,9 @@ "dev": true }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", @@ -10684,15 +10691,15 @@ } }, "node_modules/stylelint": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.0.1.tgz", - "integrity": "sha512-nPO7f7JBxX0gPwdQs1fBQL+b0PabHykxSQ9HtpobbtV7pe2lb/nmlqxKepPUwHJTi9P9iu+Hkwt1mdmOnkkTVw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.2.0.tgz", + "integrity": "sha512-gwqU5AkIb52wrAzzn+359S3NIJDMl02TXLUaV2tzA/L6jUdpTwNt+MCxHlc8+Hb2bUHlYVo92YeSIryF2gJthA==", "dev": true, "dependencies": { - "@csstools/css-parser-algorithms": "^2.3.2", - "@csstools/css-tokenizer": "^2.2.1", - "@csstools/media-query-list-parser": "^2.1.5", - "@csstools/selector-specificity": "^3.0.0", + "@csstools/css-parser-algorithms": "^2.5.0", + "@csstools/css-tokenizer": "^2.2.3", + "@csstools/media-query-list-parser": "^2.1.7", + "@csstools/selector-specificity": "^3.0.1", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", @@ -10701,7 +10708,7 @@ "debug": "^4.3.4", "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^7.0.2", + "file-entry-cache": "^8.0.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", @@ -10711,14 +10718,14 @@ "is-plain-object": "^5.0.0", "known-css-properties": "^0.29.0", "mathml-tag-names": "^2.1.3", - "meow": "^12.1.1", + "meow": "^13.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.32", + "postcss": "^8.4.33", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^7.0.0", - "postcss-selector-parser": "^6.0.13", + "postcss-selector-parser": "^6.0.15", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -10813,15 +10820,29 @@ } }, "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.2.tgz", - "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.2.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=16.0.0" + } + }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.0.tgz", + "integrity": "sha512-EryKbCE/wxpxKniQlyas6PY1I9vwtF3uCBweX+N8KYTCn3Y12RTGtQAJ/bd5pl7kxUAc8v/R3Ake/N17OZiFqA==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4", + "rimraf": "^5.0.5" + }, + "engines": { + "node": ">=16" } }, "node_modules/stylelint/node_modules/glob-parent": { @@ -10837,12 +10858,12 @@ } }, "node_modules/stylelint/node_modules/meow": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.1.0.tgz", + "integrity": "sha512-o5R/R3Tzxq0PJ3v3qcQJtSvSE9nKOLSAaDuuoMzDVuGTwHdccMWcYomh9Xolng2tjT6O/Y83d+0coVGof6tqmA==", "dev": true, "engines": { - "node": ">=16.10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10857,6 +10878,24 @@ "node": ">=8" } }, + "node_modules/stylelint/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/stylelint/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -11091,9 +11130,9 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -11281,15 +11320,15 @@ } }, "node_modules/typedoc": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.4.tgz", - "integrity": "sha512-Du9ImmpBCw54bX275yJrxPVnjdIyJO/84co0/L9mwe0R3G4FSR6rQ09AlXVRvZEGMUg09+z/usc8mgygQ1aidA==", + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.7.tgz", + "integrity": "sha512-m6A6JjQRg39p2ZVRIN3NKXgrN8vzlHhOS+r9ymUYtcUP/TIQPvWSq7YgE5ZjASfv5Vd5BW5xrir6Gm2XNNcOow==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", "minimatch": "^9.0.3", - "shiki": "^0.14.1" + "shiki": "^0.14.7" }, "bin": { "typedoc": "bin/typedoc" @@ -11315,9 +11354,9 @@ } }, "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.0.0.tgz", + "integrity": "sha512-DffL94LsNOccVn4hyfRe5rdKa273swqeA5DJpMOeFmEn1wCDc7nAbbB0gXlgBCL7TNzeTv6G7XVWzan7iJtfig==", "dev": true }, "node_modules/uhyphen": { @@ -11488,6 +11527,16 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/validate-npm-package-name": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", @@ -11561,20 +11610,20 @@ } }, "node_modules/weapon-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/weapon-regex/-/weapon-regex-1.1.1.tgz", - "integrity": "sha512-b0RmqduiSUKyKFamrpU+UK78Jm65/6CgKq1zoWFaS9PM7vwNK4RWrjmX1jREs3pLmG7botsgMLVOltxDR7RGRw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/weapon-regex/-/weapon-regex-1.3.0.tgz", + "integrity": "sha512-0bvJynFMAedPFDRPPEDXAS4ZvlsRligfvpPPpB7Efgnf6xKw8/O6qHfdYLa0fFuOaHTQuX1sXeRX/DsqRmu7bA==", "dev": true }, "node_modules/web-ext": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-7.9.0.tgz", - "integrity": "sha512-oWMiM3e+u5E8X7aUMgQ0BCGjlbZt4XwF6ExAXsXx9Btdz3nLmUY/4eKEZA1J+2T7WhCdRwN7Pdh2VKMej/pthQ==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-7.11.0.tgz", + "integrity": "sha512-EG6YXHITNDJB/h6Rc5FF08eMoN45sZPBBIIlEraBzxJ0RdJZ8Z3xvUUawbDwt+mowfv9X0XRWlLSwdWbRKgojg==", "dev": true, "dependencies": { "@babel/runtime": "7.21.0", "@devicefarmer/adbkit": "3.2.3", - "addons-linter": "6.19.0", + "addons-linter": "6.21.0", "bunyan": "1.8.15", "camelcase": "7.0.1", "chrome-launcher": "0.15.1", @@ -11583,7 +11632,7 @@ "es6-error": "4.1.1", "firefox-profile": "4.3.2", "fs-extra": "11.1.0", - "fx-runner": "1.3.0", + "fx-runner": "1.4.0", "import-fresh": "3.3.0", "jose": "4.13.1", "mkdirp": "1.0.4", @@ -11802,9 +11851,9 @@ } }, "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz", + "integrity": "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==", "dev": true, "engines": { "node": ">= 8" @@ -12050,9 +12099,9 @@ } }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index 55931731..61ecdd2e 100644 --- a/package.json +++ b/package.json @@ -39,44 +39,44 @@ "clean": "node .script/clean.js" }, "dependencies": { - "linkedom": "0.16.4" + "linkedom": "0.16.8" }, "devDependencies": { "@prantlf/jsonlint": "14.0.3", "@prettier/plugin-xml": "3.2.2", - "@stryker-mutator/core": "8.0.0", - "@stryker-mutator/mocha-runner": "8.0.0", + "@stryker-mutator/core": "8.2.2", + "@stryker-mutator/mocha-runner": "8.2.2", "@types/firefox-webext-browser": "120.0.0", "@types/jsdom": "21.1.6", "@types/mocha": "10.0.6", - "@types/sinon": "17.0.2", - "addons-linter": "6.19.0", - "eslint": "8.55.0", + "@types/sinon": "17.0.3", + "addons-linter": "6.21.0", + "eslint": "8.56.0", "eslint-plugin-array-func": "4.0.0", "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-import": "2.29.0", - "eslint-plugin-jsdoc": "46.9.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsdoc": "48.0.4", "eslint-plugin-mocha": "10.2.0", - "eslint-plugin-n": "16.3.1", + "eslint-plugin-n": "16.6.2", "eslint-plugin-no-unsanitized": "4.0.2", "eslint-plugin-promise": "6.1.1", - "eslint-plugin-regexp": "2.1.2", - "eslint-plugin-unicorn": "49.0.0", + "eslint-plugin-regexp": "2.2.0", + "eslint-plugin-unicorn": "50.0.1", "htmlhint": "1.1.4", - "jsdom": "23.0.1", - "markdownlint": "0.32.1", - "metalint": "0.14.1", + "jsdom": "24.0.0", + "markdownlint": "0.33.0", + "metalint": "0.15.0", "mocha": "10.2.0", "mock-socket": "9.3.1", "npm-package-json-lint": "7.1.0", - "prettier": "3.1.0", + "prettier": "3.2.4", "purgecss": "5.0.0", "sinon": "17.0.1", - "stylelint": "16.0.1", + "stylelint": "16.2.0", "stylelint-order": "6.0.4", - "typedoc": "0.25.4", + "typedoc": "0.25.7", "typescript": "5.3.3", - "web-ext": "7.9.0", + "web-ext": "7.11.0", "yaml-lint": "1.7.0" }, "engines": { diff --git a/src/core/labeller/dailymotion.js b/src/core/labeller/dailymotion.js index 3cc0556d..05a6ffaa 100644 --- a/src/core/labeller/dailymotion.js +++ b/src/core/labeller/dailymotion.js @@ -16,7 +16,9 @@ const action = async function (url) { const response = await fetch(url); const text = await response.text(); const doc = new DOMParser().parseFromString(text, "text/html"); - const label = doc.querySelector('meta[property="og:title"]').content; + const label = /** @type {HTMLMetaElement} */ ( + doc.querySelector('meta[property="og:title"]') + ).content; return label.slice(0, label.lastIndexOf(" - ")); }; export const extract = matchPattern(action, "*://www.dailymotion.com/video/*"); diff --git a/src/core/labeller/plugin/vtmgo.js b/src/core/labeller/plugin/vtmgo.js index d4ce085d..ba6d6a51 100644 --- a/src/core/labeller/plugin/vtmgo.js +++ b/src/core/labeller/plugin/vtmgo.js @@ -18,8 +18,8 @@ import { matchPattern } from "../../tools/matchpattern.js"; * undefined. */ const actionEpisode = function ({ pathname }, { metaExtract }) { - // Enlever le nom de domaine, car un bogue dans Firefox le déplace dans le - // chemin. https://bugzil.la/1374505 + // Enlever le nom de domaine, car un bogue dans Chromium le déplace dans le + // chemin. https://crbug.com/1416006 const episodeId = pathname.replace("//plugin.video.vtm.go", "").slice(23); return metaExtract(new URL(`https://vtm.be/vtmgo/afspelen/e${episodeId}`)); }; @@ -39,8 +39,8 @@ export const extractEpisode = matchPattern( * undefined. */ const actionMovie = function ({ pathname }, { metaExtract }) { - // Enlever le nom de domaine, car un bogue dans Firefox le déplace dans le - // chemin. https://bugzil.la/1374505 + // Enlever le nom de domaine, car un bogue dans Chromium le déplace dans le + // chemin. https://crbug.com/1416006 const movieId = pathname.replace("//plugin.video.vtm.go", "").slice(21); return metaExtract(new URL(`https://vtm.be/vtmgo/afspelen/m${movieId}`)); }; diff --git a/src/core/labeller/vimeo.js b/src/core/labeller/vimeo.js index e4b6bc7d..d803c476 100644 --- a/src/core/labeller/vimeo.js +++ b/src/core/labeller/vimeo.js @@ -16,6 +16,8 @@ const action = async function (url) { const response = await fetch(url); const text = await response.text(); const doc = new DOMParser().parseFromString(text, "text/html"); - return doc.querySelector('meta[property="og:title"]').content; + return /** @type {HTMLMetaElement} */ ( + doc.querySelector('meta[property="og:title"]') + ).content; }; export const extract = matchPattern(action, "*://vimeo.com/*"); diff --git a/src/core/labeller/vtmgo.js b/src/core/labeller/vtmgo.js index 0596b11d..1b7d09cb 100644 --- a/src/core/labeller/vtmgo.js +++ b/src/core/labeller/vtmgo.js @@ -17,8 +17,8 @@ const action = async function (url) { const response = await fetch(url); const text = await response.text(); const doc = new DOMParser().parseFromString(text, "text/html"); - return /** @type {string|undefined} */ ( - doc.querySelector("h1.player__title")?.textContent - ); + return /** @type {HTMLHeadingElement|null} */ ( + doc.querySelector("h1.player__title") + )?.textContent; }; export const extract = matchPattern(action, "*://vtm.be/vtmgo/afspelen/*"); diff --git a/src/core/labeller/youtube.js b/src/core/labeller/youtube.js index 4c0d20bf..2b8f74be 100644 --- a/src/core/labeller/youtube.js +++ b/src/core/labeller/youtube.js @@ -19,7 +19,9 @@ const actionVideo = async function (url) { const text = await response.text(); const doc = new DOMParser().parseFromString(text, "text/html"); return ( - doc.querySelector('meta[property="og:title"]')?.content ?? + /** @type {HTMLMetaElement|null} */ ( + doc.querySelector('meta[property="og:title"]') + )?.content ?? browser.i18n.getMessage("labeller_youtube_unavailable") ); } diff --git a/src/core/tools/jsonrpc.js b/src/core/tools/jsonrpc.js index 98d8a35c..8e38871a 100644 --- a/src/core/tools/jsonrpc.js +++ b/src/core/tools/jsonrpc.js @@ -95,7 +95,7 @@ export const JSONRPC = class extends EventTarget { JSON.stringify({ jsonrpc: "2.0", method, - ...(undefined === params ? {} : { params }), + params, id: this.#id, }), ); diff --git a/src/core/tools/matchpattern.js b/src/core/tools/matchpattern.js index 11620c12..5b148834 100644 --- a/src/core/tools/matchpattern.js +++ b/src/core/tools/matchpattern.js @@ -38,8 +38,8 @@ export const compile = function (pattern) { /** * Ajoute un filtre sur l'URL en paramètre d'une fonction. * - * @param {Function} func La fonction qui sera filtrée. - * @param {string[]} patterns Les modèles de correspondance pour filtrer l'URL. + * @param {Function} func La fonction qui sera filtrée. + * @param {...string} patterns Les modèles de correspondance pour filtrer l'URL. * @returns {Function} La fonction filtrée. * @see https://developer.mozilla.org/Add-ons/WebExtensions/Match_patterns */ @@ -49,8 +49,8 @@ export const matchPattern = function (func, ...patterns) { /** * Enrobe la fonction avec un filtre. * - * @param {URL} url L'URL qui sera filtrée. - * @param {any[]} others Les autres paramètres. + * @param {URL} url L'URL qui sera filtrée. + * @param {...any} others Les autres paramètres. * @returns {Promise} Une promesse contenant le retour de la * fonction ; ou undefined si * l'URL ne respecte pas un des modèles de diff --git a/src/polyfill/clipboard.js b/src/polyfill/clipboard.js index b5855add..ffe4f2e8 100644 --- a/src/polyfill/clipboard.js +++ b/src/polyfill/clipboard.js @@ -6,7 +6,8 @@ // La méthode navigator.clipboard.readText() (pour lire dans le presse-papier) // ne fonctionne pas dans Chromium car la permission "clipboardRead" s'applique -// seulement à document.execCommand("paste"). https://crbug.com/1063219 +// seulement à document.execCommand("paste"). https://crbug.com/1425583 +// https://crbug.com/1063219 (ce bogue n'est plus accessible) const { name } = await browser.runtime.getBrowserInfo(); if ("Chromium" === name) { navigator.clipboard.readText = () => { diff --git a/src/polyfill/lib/linkedom.js b/src/polyfill/lib/linkedom.js index e7ee3bdf..47aaa3d6 100644 --- a/src/polyfill/lib/linkedom.js +++ b/src/polyfill/lib/linkedom.js @@ -82,6 +82,7 @@ var xmlDecodeTree = new Uint16Array( var _a; const decodeMap = new Map([ [0, 65533], + // C1 Unicode control character reference replacements [128, 8364], [130, 8218], [131, 402], @@ -110,6 +111,9 @@ const decodeMap = new Map([ [158, 382], [159, 376], ]); +/** + * Polyfill for `String.fromCodePoint`. It is used to create a string from a Unicode code point. + */ const fromCodePoint = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins (_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : function (codePoint) { @@ -122,6 +126,11 @@ const fromCodePoint = output += String.fromCharCode(codePoint); return output; }; +/** + * Replace the given code point with a replacement character if it is a + * surrogate or is outside the valid range. Otherwise return the code + * point unchanged. + */ function replaceCodePoint(codePoint) { var _a; if ((codePoint >= 0xd800 && codePoint <= 0xdfff) || codePoint > 0x10ffff) { @@ -134,20 +143,419 @@ var CharCodes$1; (function (CharCodes) { CharCodes[CharCodes["NUM"] = 35] = "NUM"; CharCodes[CharCodes["SEMI"] = 59] = "SEMI"; + CharCodes[CharCodes["EQUALS"] = 61] = "EQUALS"; CharCodes[CharCodes["ZERO"] = 48] = "ZERO"; CharCodes[CharCodes["NINE"] = 57] = "NINE"; CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A"; CharCodes[CharCodes["LOWER_F"] = 102] = "LOWER_F"; CharCodes[CharCodes["LOWER_X"] = 120] = "LOWER_X"; - /** Bit that needs to be set to convert an upper case ASCII character to lower case */ - CharCodes[CharCodes["To_LOWER_BIT"] = 32] = "To_LOWER_BIT"; + CharCodes[CharCodes["LOWER_Z"] = 122] = "LOWER_Z"; + CharCodes[CharCodes["UPPER_A"] = 65] = "UPPER_A"; + CharCodes[CharCodes["UPPER_F"] = 70] = "UPPER_F"; + CharCodes[CharCodes["UPPER_Z"] = 90] = "UPPER_Z"; })(CharCodes$1 || (CharCodes$1 = {})); +/** Bit that needs to be set to convert an upper case ASCII character to lower case */ +const TO_LOWER_BIT = 0b100000; var BinTrieFlags; (function (BinTrieFlags) { BinTrieFlags[BinTrieFlags["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH"; BinTrieFlags[BinTrieFlags["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH"; BinTrieFlags[BinTrieFlags["JUMP_TABLE"] = 127] = "JUMP_TABLE"; })(BinTrieFlags || (BinTrieFlags = {})); +function isNumber(code) { + return code >= CharCodes$1.ZERO && code <= CharCodes$1.NINE; +} +function isHexadecimalCharacter(code) { + return ((code >= CharCodes$1.UPPER_A && code <= CharCodes$1.UPPER_F) || + (code >= CharCodes$1.LOWER_A && code <= CharCodes$1.LOWER_F)); +} +function isAsciiAlphaNumeric(code) { + return ((code >= CharCodes$1.UPPER_A && code <= CharCodes$1.UPPER_Z) || + (code >= CharCodes$1.LOWER_A && code <= CharCodes$1.LOWER_Z) || + isNumber(code)); +} +/** + * Checks if the given character is a valid end character for an entity in an attribute. + * + * Attribute values that aren't terminated properly aren't parsed, and shouldn't lead to a parser error. + * See the example in https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state + */ +function isEntityInAttributeInvalidEnd(code) { + return code === CharCodes$1.EQUALS || isAsciiAlphaNumeric(code); +} +var EntityDecoderState; +(function (EntityDecoderState) { + EntityDecoderState[EntityDecoderState["EntityStart"] = 0] = "EntityStart"; + EntityDecoderState[EntityDecoderState["NumericStart"] = 1] = "NumericStart"; + EntityDecoderState[EntityDecoderState["NumericDecimal"] = 2] = "NumericDecimal"; + EntityDecoderState[EntityDecoderState["NumericHex"] = 3] = "NumericHex"; + EntityDecoderState[EntityDecoderState["NamedEntity"] = 4] = "NamedEntity"; +})(EntityDecoderState || (EntityDecoderState = {})); +var DecodingMode; +(function (DecodingMode) { + /** Entities in text nodes that can end with any character. */ + DecodingMode[DecodingMode["Legacy"] = 0] = "Legacy"; + /** Only allow entities terminated with a semicolon. */ + DecodingMode[DecodingMode["Strict"] = 1] = "Strict"; + /** Entities in attributes have limitations on ending characters. */ + DecodingMode[DecodingMode["Attribute"] = 2] = "Attribute"; +})(DecodingMode || (DecodingMode = {})); +/** + * Token decoder with support of writing partial entities. + */ +class EntityDecoder { + constructor( + /** The tree used to decode entities. */ + decodeTree, + /** + * The function that is called when a codepoint is decoded. + * + * For multi-byte named entities, this will be called multiple times, + * with the second codepoint, and the same `consumed` value. + * + * @param codepoint The decoded codepoint. + * @param consumed The number of bytes consumed by the decoder. + */ + emitCodePoint, + /** An object that is used to produce errors. */ + errors) { + this.decodeTree = decodeTree; + this.emitCodePoint = emitCodePoint; + this.errors = errors; + /** The current state of the decoder. */ + this.state = EntityDecoderState.EntityStart; + /** Characters that were consumed while parsing an entity. */ + this.consumed = 1; + /** + * The result of the entity. + * + * Either the result index of a numeric entity, or the codepoint of a + * numeric entity. + */ + this.result = 0; + /** The current index in the decode tree. */ + this.treeIndex = 0; + /** The number of characters that were consumed in excess. */ + this.excess = 1; + /** The mode in which the decoder is operating. */ + this.decodeMode = DecodingMode.Strict; + } + /** Resets the instance to make it reusable. */ + startEntity(decodeMode) { + this.decodeMode = decodeMode; + this.state = EntityDecoderState.EntityStart; + this.result = 0; + this.treeIndex = 0; + this.excess = 1; + this.consumed = 1; + } + /** + * Write an entity to the decoder. This can be called multiple times with partial entities. + * If the entity is incomplete, the decoder will return -1. + * + * Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the + * entity is incomplete, and resume when the next string is written. + * + * @param string The string containing the entity (or a continuation of the entity). + * @param offset The offset at which the entity begins. Should be 0 if this is not the first call. + * @returns The number of characters that were consumed, or -1 if the entity is incomplete. + */ + write(str, offset) { + switch (this.state) { + case EntityDecoderState.EntityStart: { + if (str.charCodeAt(offset) === CharCodes$1.NUM) { + this.state = EntityDecoderState.NumericStart; + this.consumed += 1; + return this.stateNumericStart(str, offset + 1); + } + this.state = EntityDecoderState.NamedEntity; + return this.stateNamedEntity(str, offset); + } + case EntityDecoderState.NumericStart: { + return this.stateNumericStart(str, offset); + } + case EntityDecoderState.NumericDecimal: { + return this.stateNumericDecimal(str, offset); + } + case EntityDecoderState.NumericHex: { + return this.stateNumericHex(str, offset); + } + case EntityDecoderState.NamedEntity: { + return this.stateNamedEntity(str, offset); + } + } + } + /** + * Switches between the numeric decimal and hexadecimal states. + * + * Equivalent to the `Numeric character reference state` in the HTML spec. + * + * @param str The string containing the entity (or a continuation of the entity). + * @param offset The current offset. + * @returns The number of characters that were consumed, or -1 if the entity is incomplete. + */ + stateNumericStart(str, offset) { + if (offset >= str.length) { + return -1; + } + if ((str.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes$1.LOWER_X) { + this.state = EntityDecoderState.NumericHex; + this.consumed += 1; + return this.stateNumericHex(str, offset + 1); + } + this.state = EntityDecoderState.NumericDecimal; + return this.stateNumericDecimal(str, offset); + } + addToNumericResult(str, start, end, base) { + if (start !== end) { + const digitCount = end - start; + this.result = + this.result * Math.pow(base, digitCount) + + parseInt(str.substr(start, digitCount), base); + this.consumed += digitCount; + } + } + /** + * Parses a hexadecimal numeric entity. + * + * Equivalent to the `Hexademical character reference state` in the HTML spec. + * + * @param str The string containing the entity (or a continuation of the entity). + * @param offset The current offset. + * @returns The number of characters that were consumed, or -1 if the entity is incomplete. + */ + stateNumericHex(str, offset) { + const startIdx = offset; + while (offset < str.length) { + const char = str.charCodeAt(offset); + if (isNumber(char) || isHexadecimalCharacter(char)) { + offset += 1; + } + else { + this.addToNumericResult(str, startIdx, offset, 16); + return this.emitNumericEntity(char, 3); + } + } + this.addToNumericResult(str, startIdx, offset, 16); + return -1; + } + /** + * Parses a decimal numeric entity. + * + * Equivalent to the `Decimal character reference state` in the HTML spec. + * + * @param str The string containing the entity (or a continuation of the entity). + * @param offset The current offset. + * @returns The number of characters that were consumed, or -1 if the entity is incomplete. + */ + stateNumericDecimal(str, offset) { + const startIdx = offset; + while (offset < str.length) { + const char = str.charCodeAt(offset); + if (isNumber(char)) { + offset += 1; + } + else { + this.addToNumericResult(str, startIdx, offset, 10); + return this.emitNumericEntity(char, 2); + } + } + this.addToNumericResult(str, startIdx, offset, 10); + return -1; + } + /** + * Validate and emit a numeric entity. + * + * Implements the logic from the `Hexademical character reference start + * state` and `Numeric character reference end state` in the HTML spec. + * + * @param lastCp The last code point of the entity. Used to see if the + * entity was terminated with a semicolon. + * @param expectedLength The minimum number of characters that should be + * consumed. Used to validate that at least one digit + * was consumed. + * @returns The number of characters that were consumed. + */ + emitNumericEntity(lastCp, expectedLength) { + var _a; + // Ensure we consumed at least one digit. + if (this.consumed <= expectedLength) { + (_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed); + return 0; + } + // Figure out if this is a legit end of the entity + if (lastCp === CharCodes$1.SEMI) { + this.consumed += 1; + } + else if (this.decodeMode === DecodingMode.Strict) { + return 0; + } + this.emitCodePoint(replaceCodePoint(this.result), this.consumed); + if (this.errors) { + if (lastCp !== CharCodes$1.SEMI) { + this.errors.missingSemicolonAfterCharacterReference(); + } + this.errors.validateNumericCharacterReference(this.result); + } + return this.consumed; + } + /** + * Parses a named entity. + * + * Equivalent to the `Named character reference state` in the HTML spec. + * + * @param str The string containing the entity (or a continuation of the entity). + * @param offset The current offset. + * @returns The number of characters that were consumed, or -1 if the entity is incomplete. + */ + stateNamedEntity(str, offset) { + const { decodeTree } = this; + let current = decodeTree[this.treeIndex]; + // The mask is the number of bytes of the value, including the current byte. + let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14; + for (; offset < str.length; offset++, this.excess++) { + const char = str.charCodeAt(offset); + this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char); + if (this.treeIndex < 0) { + return this.result === 0 || + // If we are parsing an attribute + (this.decodeMode === DecodingMode.Attribute && + // We shouldn't have consumed any characters after the entity, + (valueLength === 0 || + // And there should be no invalid characters. + isEntityInAttributeInvalidEnd(char))) + ? 0 + : this.emitNotTerminatedNamedEntity(); + } + current = decodeTree[this.treeIndex]; + valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14; + // If the branch is a value, store it and continue + if (valueLength !== 0) { + // If the entity is terminated by a semicolon, we are done. + if (char === CharCodes$1.SEMI) { + return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess); + } + // If we encounter a non-terminated (legacy) entity while parsing strictly, then ignore it. + if (this.decodeMode !== DecodingMode.Strict) { + this.result = this.treeIndex; + this.consumed += this.excess; + this.excess = 0; + } + } + } + return -1; + } + /** + * Emit a named entity that was not terminated with a semicolon. + * + * @returns The number of characters consumed. + */ + emitNotTerminatedNamedEntity() { + var _a; + const { result, decodeTree } = this; + const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14; + this.emitNamedEntityData(result, valueLength, this.consumed); + (_a = this.errors) === null || _a === void 0 ? void 0 : _a.missingSemicolonAfterCharacterReference(); + return this.consumed; + } + /** + * Emit a named entity. + * + * @param result The index of the entity in the decode tree. + * @param valueLength The number of bytes in the entity. + * @param consumed The number of characters consumed. + * + * @returns The number of characters consumed. + */ + emitNamedEntityData(result, valueLength, consumed) { + const { decodeTree } = this; + this.emitCodePoint(valueLength === 1 + ? decodeTree[result] & ~BinTrieFlags.VALUE_LENGTH + : decodeTree[result + 1], consumed); + if (valueLength === 3) { + // For multi-byte values, we need to emit the second byte. + this.emitCodePoint(decodeTree[result + 2], consumed); + } + return consumed; + } + /** + * Signal to the parser that the end of the input was reached. + * + * Remaining data will be emitted and relevant errors will be produced. + * + * @returns The number of characters consumed. + */ + end() { + var _a; + switch (this.state) { + case EntityDecoderState.NamedEntity: { + // Emit a named entity if we have one. + return this.result !== 0 && + (this.decodeMode !== DecodingMode.Attribute || + this.result === this.treeIndex) + ? this.emitNotTerminatedNamedEntity() + : 0; + } + // Otherwise, emit a numeric entity if we have one. + case EntityDecoderState.NumericDecimal: { + return this.emitNumericEntity(0, 2); + } + case EntityDecoderState.NumericHex: { + return this.emitNumericEntity(0, 3); + } + case EntityDecoderState.NumericStart: { + (_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed); + return 0; + } + case EntityDecoderState.EntityStart: { + // Return 0 if we have no entity. + return 0; + } + } + } +} +/** + * Creates a function that decodes entities in a string. + * + * @param decodeTree The decode tree. + * @returns A function that decodes entities in a string. + */ +function getDecoder(decodeTree) { + let ret = ""; + const decoder = new EntityDecoder(decodeTree, (str) => (ret += fromCodePoint(str))); + return function decodeWithTrie(str, decodeMode) { + let lastIndex = 0; + let offset = 0; + while ((offset = str.indexOf("&", offset)) >= 0) { + ret += str.slice(lastIndex, offset); + decoder.startEntity(decodeMode); + const len = decoder.write(str, + // Skip the "&" + offset + 1); + if (len < 0) { + lastIndex = offset + decoder.end(); + break; + } + lastIndex = offset + len; + // If `len` is 0, skip the current `&` and continue. + offset = len === 0 ? lastIndex + 1 : lastIndex; + } + const result = ret + str.slice(lastIndex); + // Make sure we don't keep a reference to the final string. + ret = ""; + return result; + }; +} +/** + * Determines the branch of the current node that is taken given the current + * character. This function is used to traverse the trie. + * + * @param decodeTree The trie. + * @param current The current node. + * @param nodeIdx The index right after the current node and its value. + * @param char The current character. + * @returns The index of the next node, or -1 if no branch is taken. + */ function determineBranch(decodeTree, current, nodeIdx, char) { const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7; const jumpOffset = current & BinTrieFlags.JUMP_TABLE; @@ -181,6 +589,8 @@ function determineBranch(decodeTree, current, nodeIdx, char) { } return -1; } +getDecoder(htmlDecodeTree); +getDecoder(xmlDecodeTree); var CharCodes; (function (CharCodes) { @@ -190,7 +600,7 @@ var CharCodes; CharCodes[CharCodes["CarriageReturn"] = 13] = "CarriageReturn"; CharCodes[CharCodes["Space"] = 32] = "Space"; CharCodes[CharCodes["ExclamationMark"] = 33] = "ExclamationMark"; - CharCodes[CharCodes["Num"] = 35] = "Num"; + CharCodes[CharCodes["Number"] = 35] = "Number"; CharCodes[CharCodes["Amp"] = 38] = "Amp"; CharCodes[CharCodes["SingleQuote"] = 39] = "SingleQuote"; CharCodes[CharCodes["DoubleQuote"] = 34] = "DoubleQuote"; @@ -244,11 +654,7 @@ var State; State[State["BeforeSpecialS"] = 22] = "BeforeSpecialS"; State[State["SpecialStartSequence"] = 23] = "SpecialStartSequence"; State[State["InSpecialTag"] = 24] = "InSpecialTag"; - State[State["BeforeEntity"] = 25] = "BeforeEntity"; - State[State["BeforeNumericEntity"] = 26] = "BeforeNumericEntity"; - State[State["InNamedEntity"] = 27] = "InNamedEntity"; - State[State["InNumericEntity"] = 28] = "InNumericEntity"; - State[State["InHexEntity"] = 29] = "InHexEntity"; + State[State["InEntity"] = 25] = "InEntity"; })(State || (State = {})); function isWhitespace$1(c) { return (c === CharCodes.Space || @@ -260,17 +666,10 @@ function isWhitespace$1(c) { function isEndOfTagSection(c) { return c === CharCodes.Slash || c === CharCodes.Gt || isWhitespace$1(c); } -function isNumber(c) { - return c >= CharCodes.Zero && c <= CharCodes.Nine; -} function isASCIIAlpha(c) { return ((c >= CharCodes.LowerA && c <= CharCodes.LowerZ) || (c >= CharCodes.UpperA && c <= CharCodes.UpperZ)); } -function isHexDigit(c) { - return ((c >= CharCodes.UpperA && c <= CharCodes.UpperF) || - (c >= CharCodes.LowerA && c <= CharCodes.LowerF)); -} var QuoteType; (function (QuoteType) { QuoteType[QuoteType["NoValue"] = 0] = "NoValue"; @@ -303,6 +702,8 @@ class Tokenizer { this.sectionStart = 0; /** The index within the buffer that we are currently looking at. */ this.index = 0; + /** The start of the last entity. */ + this.entityStart = 0; /** Some behavior, eg. when decoding entities, is done while we are in another state. This keeps track of the other state type. */ this.baseState = State.Text; /** For special parsing behavior inside of script and style tags. */ @@ -311,15 +712,11 @@ class Tokenizer { this.running = true; /** The offset of the current buffer. */ this.offset = 0; + this.currentSequence = undefined; this.sequenceIndex = 0; - this.trieIndex = 0; - this.trieCurrent = 0; - /** For named entities, the index of the value. For numeric entities, the code point. */ - this.entityResult = 0; - this.entityExcess = 0; this.xmlMode = xmlMode; this.decodeEntities = decodeEntities; - this.entityTrie = xmlMode ? xmlDecodeTree : htmlDecodeTree; + this.entityDecoder = new EntityDecoder(xmlMode ? xmlDecodeTree : htmlDecodeTree, (cp, consumed) => this.emitCodePoint(cp, consumed)); } reset() { this.state = State.Text; @@ -349,18 +746,6 @@ class Tokenizer { this.parse(); } } - /** - * The current index within all of the written data. - */ - getIndex() { - return this.index; - } - /** - * The start of the current section. - */ - getSectionStart() { - return this.sectionStart; - } stateText(c) { if (c === CharCodes.Lt || (!this.decodeEntities && this.fastForwardTo(CharCodes.Lt))) { @@ -371,7 +756,7 @@ class Tokenizer { this.sectionStart = this.index; } else if (this.decodeEntities && c === CharCodes.Amp) { - this.state = State.BeforeEntity; + this.startEntity(); } } stateSpecialStartSequence(c) { @@ -418,7 +803,7 @@ class Tokenizer { if (this.currentSequence === Sequences.TitleEnd) { // We have to parse entities in tags. if (this.decodeEntities && c === CharCodes.Amp) { - this.state = State.BeforeEntity; + this.startEntity(); } } else if (this.fastForwardTo(CharCodes.Lt)) { @@ -590,7 +975,6 @@ class Tokenizer { else { this.state = State.Text; } - this.baseState = this.state; this.sectionStart = this.index + 1; } else if (c === CharCodes.Slash) { @@ -605,7 +989,6 @@ class Tokenizer { if (c === CharCodes.Gt) { this.cbs.onselfclosingtag(this.index); this.state = State.Text; - this.baseState = State.Text; this.sectionStart = this.index + 1; this.isSpecial = false; // Reset special state, in case of self-closing special tags } @@ -663,8 +1046,7 @@ class Tokenizer { this.state = State.BeforeAttributeName; } else if (this.decodeEntities && c === CharCodes.Amp) { - this.baseState = this.state; - this.state = State.BeforeEntity; + this.startEntity(); } } stateInAttributeValueDoubleQuotes(c) { @@ -682,8 +1064,7 @@ class Tokenizer { this.stateBeforeAttributeName(c); } else if (this.decodeEntities && c === CharCodes.Amp) { - this.baseState = this.state; - this.state = State.BeforeEntity; + this.startEntity(); } } stateBeforeDeclaration(c) { @@ -744,146 +1125,31 @@ class Tokenizer { this.stateInTagName(c); // Consume the token again } } - stateBeforeEntity(c) { - // Start excess with 1 to include the '&' - this.entityExcess = 1; - this.entityResult = 0; - if (c === CharCodes.Num) { - this.state = State.BeforeNumericEntity; - } - else if (c === CharCodes.Amp) ; - else { - this.trieIndex = 0; - this.trieCurrent = this.entityTrie[0]; - this.state = State.InNamedEntity; - this.stateInNamedEntity(c); - } - } - stateInNamedEntity(c) { - this.entityExcess += 1; - this.trieIndex = determineBranch(this.entityTrie, this.trieCurrent, this.trieIndex + 1, c); - if (this.trieIndex < 0) { - this.emitNamedEntity(); - this.index--; - return; - } - this.trieCurrent = this.entityTrie[this.trieIndex]; - const masked = this.trieCurrent & BinTrieFlags.VALUE_LENGTH; - // If the branch is a value, store it and continue - if (masked) { - // The mask is the number of bytes of the value, including the current byte. - const valueLength = (masked >> 14) - 1; - // If we have a legacy entity while parsing strictly, just skip the number of bytes - if (!this.allowLegacyEntity() && c !== CharCodes.Semi) { - this.trieIndex += valueLength; - } - else { - // Add 1 as we have already incremented the excess - const entityStart = this.index - this.entityExcess + 1; - if (entityStart > this.sectionStart) { - this.emitPartial(this.sectionStart, entityStart); - } - // If this is a surrogate pair, consume the next two bytes - this.entityResult = this.trieIndex; - this.trieIndex += valueLength; - this.entityExcess = 0; - this.sectionStart = this.index + 1; - if (valueLength === 0) { - this.emitNamedEntity(); - } - } - } - } - emitNamedEntity() { - this.state = this.baseState; - if (this.entityResult === 0) { - return; - } - const valueLength = (this.entityTrie[this.entityResult] & BinTrieFlags.VALUE_LENGTH) >> - 14; - switch (valueLength) { - case 1: - this.emitCodePoint(this.entityTrie[this.entityResult] & - ~BinTrieFlags.VALUE_LENGTH); - break; - case 2: - this.emitCodePoint(this.entityTrie[this.entityResult + 1]); - break; - case 3: { - this.emitCodePoint(this.entityTrie[this.entityResult + 1]); - this.emitCodePoint(this.entityTrie[this.entityResult + 2]); - } - } - } - stateBeforeNumericEntity(c) { - if ((c | 0x20) === CharCodes.LowerX) { - this.entityExcess++; - this.state = State.InHexEntity; - } - else { - this.state = State.InNumericEntity; - this.stateInNumericEntity(c); - } - } - emitNumericEntity(strict) { - const entityStart = this.index - this.entityExcess - 1; - const numberStart = entityStart + 2 + Number(this.state === State.InHexEntity); - if (numberStart !== this.index) { - // Emit leading data if any - if (entityStart > this.sectionStart) { - this.emitPartial(this.sectionStart, entityStart); + startEntity() { + this.baseState = this.state; + this.state = State.InEntity; + this.entityStart = this.index; + this.entityDecoder.startEntity(this.xmlMode + ? DecodingMode.Strict + : this.baseState === State.Text || + this.baseState === State.InSpecialTag + ? DecodingMode.Legacy + : DecodingMode.Attribute); + } + stateInEntity() { + const length = this.entityDecoder.write(this.buffer, this.index - this.offset); + // If `length` is positive, we are done with the entity. + if (length >= 0) { + this.state = this.baseState; + if (length === 0) { + this.index = this.entityStart; } - this.sectionStart = this.index + Number(strict); - this.emitCodePoint(replaceCodePoint(this.entityResult)); - } - this.state = this.baseState; - } - stateInNumericEntity(c) { - if (c === CharCodes.Semi) { - this.emitNumericEntity(true); - } - else if (isNumber(c)) { - this.entityResult = this.entityResult * 10 + (c - CharCodes.Zero); - this.entityExcess++; - } - else { - if (this.allowLegacyEntity()) { - this.emitNumericEntity(false); - } - else { - this.state = this.baseState; - } - this.index--; - } - } - stateInHexEntity(c) { - if (c === CharCodes.Semi) { - this.emitNumericEntity(true); - } - else if (isNumber(c)) { - this.entityResult = this.entityResult * 16 + (c - CharCodes.Zero); - this.entityExcess++; - } - else if (isHexDigit(c)) { - this.entityResult = - this.entityResult * 16 + ((c | 0x20) - CharCodes.LowerA + 10); - this.entityExcess++; } else { - if (this.allowLegacyEntity()) { - this.emitNumericEntity(false); - } - else { - this.state = this.baseState; - } - this.index--; + // Mark buffer as consumed. + this.index = this.offset + this.buffer.length - 1; } } - allowLegacyEntity() { - return (!this.xmlMode && - (this.baseState === State.Text || - this.baseState === State.InSpecialTag)); - } /** * Remove data that has already been consumed from the buffer. */ @@ -914,111 +1180,127 @@ class Tokenizer { parse() { while (this.shouldContinue()) { const c = this.buffer.charCodeAt(this.index - this.offset); - if (this.state === State.Text) { - this.stateText(c); - } - else if (this.state === State.SpecialStartSequence) { - this.stateSpecialStartSequence(c); - } - else if (this.state === State.InSpecialTag) { - this.stateInSpecialTag(c); - } - else if (this.state === State.CDATASequence) { - this.stateCDATASequence(c); - } - else if (this.state === State.InAttributeValueDq) { - this.stateInAttributeValueDoubleQuotes(c); - } - else if (this.state === State.InAttributeName) { - this.stateInAttributeName(c); - } - else if (this.state === State.InCommentLike) { - this.stateInCommentLike(c); - } - else if (this.state === State.InSpecialComment) { - this.stateInSpecialComment(c); - } - else if (this.state === State.BeforeAttributeName) { - this.stateBeforeAttributeName(c); - } - else if (this.state === State.InTagName) { - this.stateInTagName(c); - } - else if (this.state === State.InClosingTagName) { - this.stateInClosingTagName(c); - } - else if (this.state === State.BeforeTagName) { - this.stateBeforeTagName(c); - } - else if (this.state === State.AfterAttributeName) { - this.stateAfterAttributeName(c); - } - else if (this.state === State.InAttributeValueSq) { - this.stateInAttributeValueSingleQuotes(c); - } - else if (this.state === State.BeforeAttributeValue) { - this.stateBeforeAttributeValue(c); - } - else if (this.state === State.BeforeClosingTagName) { - this.stateBeforeClosingTagName(c); - } - else if (this.state === State.AfterClosingTagName) { - this.stateAfterClosingTagName(c); - } - else if (this.state === State.BeforeSpecialS) { - this.stateBeforeSpecialS(c); - } - else if (this.state === State.InAttributeValueNq) { - this.stateInAttributeValueNoQuotes(c); - } - else if (this.state === State.InSelfClosingTag) { - this.stateInSelfClosingTag(c); - } - else if (this.state === State.InDeclaration) { - this.stateInDeclaration(c); - } - else if (this.state === State.BeforeDeclaration) { - this.stateBeforeDeclaration(c); - } - else if (this.state === State.BeforeComment) { - this.stateBeforeComment(c); - } - else if (this.state === State.InProcessingInstruction) { - this.stateInProcessingInstruction(c); - } - else if (this.state === State.InNamedEntity) { - this.stateInNamedEntity(c); - } - else if (this.state === State.BeforeEntity) { - this.stateBeforeEntity(c); - } - else if (this.state === State.InHexEntity) { - this.stateInHexEntity(c); - } - else if (this.state === State.InNumericEntity) { - this.stateInNumericEntity(c); - } - else { - // `this._state === State.BeforeNumericEntity` - this.stateBeforeNumericEntity(c); + switch (this.state) { + case State.Text: { + this.stateText(c); + break; + } + case State.SpecialStartSequence: { + this.stateSpecialStartSequence(c); + break; + } + case State.InSpecialTag: { + this.stateInSpecialTag(c); + break; + } + case State.CDATASequence: { + this.stateCDATASequence(c); + break; + } + case State.InAttributeValueDq: { + this.stateInAttributeValueDoubleQuotes(c); + break; + } + case State.InAttributeName: { + this.stateInAttributeName(c); + break; + } + case State.InCommentLike: { + this.stateInCommentLike(c); + break; + } + case State.InSpecialComment: { + this.stateInSpecialComment(c); + break; + } + case State.BeforeAttributeName: { + this.stateBeforeAttributeName(c); + break; + } + case State.InTagName: { + this.stateInTagName(c); + break; + } + case State.InClosingTagName: { + this.stateInClosingTagName(c); + break; + } + case State.BeforeTagName: { + this.stateBeforeTagName(c); + break; + } + case State.AfterAttributeName: { + this.stateAfterAttributeName(c); + break; + } + case State.InAttributeValueSq: { + this.stateInAttributeValueSingleQuotes(c); + break; + } + case State.BeforeAttributeValue: { + this.stateBeforeAttributeValue(c); + break; + } + case State.BeforeClosingTagName: { + this.stateBeforeClosingTagName(c); + break; + } + case State.AfterClosingTagName: { + this.stateAfterClosingTagName(c); + break; + } + case State.BeforeSpecialS: { + this.stateBeforeSpecialS(c); + break; + } + case State.InAttributeValueNq: { + this.stateInAttributeValueNoQuotes(c); + break; + } + case State.InSelfClosingTag: { + this.stateInSelfClosingTag(c); + break; + } + case State.InDeclaration: { + this.stateInDeclaration(c); + break; + } + case State.BeforeDeclaration: { + this.stateBeforeDeclaration(c); + break; + } + case State.BeforeComment: { + this.stateBeforeComment(c); + break; + } + case State.InProcessingInstruction: { + this.stateInProcessingInstruction(c); + break; + } + case State.InEntity: { + this.stateInEntity(); + break; + } } this.index++; } this.cleanup(); } finish() { - if (this.state === State.InNamedEntity) { - this.emitNamedEntity(); - } - // If there is remaining data, emit it in a reasonable way - if (this.sectionStart < this.index) { - this.handleTrailingData(); + if (this.state === State.InEntity) { + this.entityDecoder.end(); + this.state = this.baseState; } + this.handleTrailingData(); this.cbs.onend(); } /** Handle any trailing data. */ handleTrailingData() { const endIndex = this.buffer.length + this.offset; + // If there is no remaining data, we are done. + if (this.sectionStart >= endIndex) { + return; + } if (this.state === State.InCommentLike) { if (this.currentSequence === Sequences.CdataEnd) { this.cbs.oncdata(this.sectionStart, endIndex, 0); @@ -1027,16 +1309,6 @@ class Tokenizer { this.cbs.oncomment(this.sectionStart, endIndex, 0); } } - else if (this.state === State.InNumericEntity && - this.allowLegacyEntity()) { - this.emitNumericEntity(false); - // All trailing data will have been consumed - } - else if (this.state === State.InHexEntity && - this.allowLegacyEntity()) { - this.emitNumericEntity(false); - // All trailing data will have been consumed - } else if (this.state === State.InTagName || this.state === State.BeforeAttributeName || this.state === State.BeforeAttributeValue || @@ -1050,22 +1322,23 @@ class Tokenizer { this.cbs.ontext(this.sectionStart, endIndex); } } - emitPartial(start, endIndex) { - if (this.baseState !== State.Text && - this.baseState !== State.InSpecialTag) { - this.cbs.onattribdata(start, endIndex); - } - else { - this.cbs.ontext(start, endIndex); - } - } - emitCodePoint(cp) { + emitCodePoint(cp, consumed) { if (this.baseState !== State.Text && this.baseState !== State.InSpecialTag) { + if (this.sectionStart < this.entityStart) { + this.cbs.onattribdata(this.sectionStart, this.entityStart); + } + this.sectionStart = this.entityStart + consumed; + this.index = this.sectionStart - 1; this.cbs.onattribentity(cp); } else { - this.cbs.ontextentity(cp); + if (this.sectionStart < this.entityStart) { + this.cbs.ontext(this.sectionStart, this.entityStart); + } + this.sectionStart = this.entityStart + consumed; + this.index = this.sectionStart - 1; + this.cbs.ontextentity(cp, this.sectionStart); } } } @@ -1184,7 +1457,6 @@ let Parser$1 = class Parser { this.attribvalue = ""; this.attribs = null; this.stack = []; - this.foreignContext = []; this.buffers = []; this.bufferOffset = 0; /** The index of the last written buffer. Used when resuming after a `pause()`. */ @@ -1192,10 +1464,12 @@ let Parser$1 = class Parser { /** Indicates whether the parser has finished running / `.end` has been called. */ this.ended = false; this.cbs = cbs !== null && cbs !== void 0 ? cbs : {}; - this.lowerCaseTagNames = (_a = options.lowerCaseTags) !== null && _a !== void 0 ? _a : !options.xmlMode; + this.htmlMode = !this.options.xmlMode; + this.lowerCaseTagNames = (_a = options.lowerCaseTags) !== null && _a !== void 0 ? _a : this.htmlMode; this.lowerCaseAttributeNames = - (_b = options.lowerCaseAttributeNames) !== null && _b !== void 0 ? _b : !options.xmlMode; + (_b = options.lowerCaseAttributeNames) !== null && _b !== void 0 ? _b : this.htmlMode; this.tokenizer = new ((_c = options.Tokenizer) !== null && _c !== void 0 ? _c : Tokenizer)(this.options, this); + this.foreignContext = [!this.htmlMode]; (_e = (_d = this.cbs).onparserinit) === null || _e === void 0 ? void 0 : _e.call(_d, this); } // Tokenizer event handlers @@ -1208,19 +1482,18 @@ let Parser$1 = class Parser { this.startIndex = endIndex; } /** @internal */ - ontextentity(cp) { + ontextentity(cp, endIndex) { var _a, _b; - /* - * Entities can be emitted on the character, or directly after. - * We use the section start here to get accurate indices. - */ - const idx = this.tokenizer.getSectionStart(); - this.endIndex = idx - 1; + this.endIndex = endIndex - 1; (_b = (_a = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a, fromCodePoint(cp)); - this.startIndex = idx; + this.startIndex = endIndex; } + /** + * Checks if the current tag is a void element. Override this if you want + * to specify your own additional void elements. + */ isVoidElement(name) { - return !this.options.xmlMode && voidElements$1.has(name); + return this.htmlMode && voidElements$1.has(name); } /** @internal */ onopentagname(start, endIndex) { @@ -1235,21 +1508,22 @@ let Parser$1 = class Parser { var _a, _b, _c, _d; this.openTagStart = this.startIndex; this.tagname = name; - const impliesClose = !this.options.xmlMode && openImpliesClose.get(name); + const impliesClose = this.htmlMode && openImpliesClose.get(name); if (impliesClose) { - while (this.stack.length > 0 && - impliesClose.has(this.stack[this.stack.length - 1])) { - const el = this.stack.pop(); - (_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, el, true); + while (this.stack.length > 0 && impliesClose.has(this.stack[0])) { + const element = this.stack.shift(); + (_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, element, true); } } if (!this.isVoidElement(name)) { - this.stack.push(name); - if (foreignContextElements.has(name)) { - this.foreignContext.push(true); - } - else if (htmlIntegrationElements.has(name)) { - this.foreignContext.push(false); + this.stack.unshift(name); + if (this.htmlMode) { + if (foreignContextElements.has(name)) { + this.foreignContext.unshift(true); + } + else if (htmlIntegrationElements.has(name)) { + this.foreignContext.unshift(false); + } } } (_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, name); @@ -1277,40 +1551,37 @@ let Parser$1 = class Parser { } /** @internal */ onclosetag(start, endIndex) { - var _a, _b, _c, _d, _e, _f; + var _a, _b, _c, _d, _e, _f, _g, _h; this.endIndex = endIndex; let name = this.getSlice(start, endIndex); if (this.lowerCaseTagNames) { name = name.toLowerCase(); } - if (foreignContextElements.has(name) || - htmlIntegrationElements.has(name)) { - this.foreignContext.pop(); + if (this.htmlMode && + (foreignContextElements.has(name) || + htmlIntegrationElements.has(name))) { + this.foreignContext.shift(); } if (!this.isVoidElement(name)) { - const pos = this.stack.lastIndexOf(name); + const pos = this.stack.indexOf(name); if (pos !== -1) { - if (this.cbs.onclosetag) { - let count = this.stack.length - pos; - while (count--) { - // We know the stack has sufficient elements. - this.cbs.onclosetag(this.stack.pop(), count !== 0); - } + for (let index = 0; index <= pos; index++) { + const element = this.stack.shift(); + // We know the stack has sufficient elements. + (_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, element, index !== pos); } - else - this.stack.length = pos; } - else if (!this.options.xmlMode && name === "p") { + else if (this.htmlMode && name === "p") { // Implicit open before close this.emitOpenTag("p"); this.closeCurrentTag(true); } } - else if (!this.options.xmlMode && name === "br") { + else if (this.htmlMode && name === "br") { // We can't use `emitOpenTag` for implicit open, as `br` would be implicitly closed. - (_b = (_a = this.cbs).onopentagname) === null || _b === void 0 ? void 0 : _b.call(_a, "br"); - (_d = (_c = this.cbs).onopentag) === null || _d === void 0 ? void 0 : _d.call(_c, "br", {}, true); - (_f = (_e = this.cbs).onclosetag) === null || _f === void 0 ? void 0 : _f.call(_e, "br", false); + (_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, "br"); + (_f = (_e = this.cbs).onopentag) === null || _f === void 0 ? void 0 : _f.call(_e, "br", {}, true); + (_h = (_g = this.cbs).onclosetag) === null || _h === void 0 ? void 0 : _h.call(_g, "br", false); } // Set `startIndex` for next node this.startIndex = endIndex + 1; @@ -1318,9 +1589,7 @@ let Parser$1 = class Parser { /** @internal */ onselfclosingtag(endIndex) { this.endIndex = endIndex; - if (this.options.xmlMode || - this.options.recognizeSelfClosing || - this.foreignContext[this.foreignContext.length - 1]) { + if (this.options.recognizeSelfClosing || this.foreignContext[0]) { this.closeCurrentTag(false); // Set `startIndex` for next node this.startIndex = endIndex + 1; @@ -1335,10 +1604,10 @@ let Parser$1 = class Parser { const name = this.tagname; this.endOpenTag(isOpenImplied); // Self-closing tags will be on the top of the stack - if (this.stack[this.stack.length - 1] === name) { + if (this.stack[0] === name) { // If the opening tag isn't implied, the closing tag has to be implied. (_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, name, !isOpenImplied); - this.stack.pop(); + this.stack.shift(); } } /** @internal */ @@ -1375,8 +1644,8 @@ let Parser$1 = class Parser { this.attribvalue = ""; } getInstructionName(value) { - const idx = value.search(reNameEnd); - let name = idx < 0 ? value : value.substr(0, idx); + const index = value.search(reNameEnd); + let name = index < 0 ? value : value.substr(0, index); if (this.lowerCaseTagNames) { name = name.toLowerCase(); } @@ -1418,7 +1687,7 @@ let Parser$1 = class Parser { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; this.endIndex = endIndex; const value = this.getSlice(start, endIndex - offset); - if (this.options.xmlMode || this.options.recognizeCDATA) { + if (!this.htmlMode || this.options.recognizeCDATA) { (_b = (_a = this.cbs).oncdatastart) === null || _b === void 0 ? void 0 : _b.call(_a); (_d = (_c = this.cbs).ontext) === null || _d === void 0 ? void 0 : _d.call(_c, value); (_f = (_e = this.cbs).oncdataend) === null || _f === void 0 ? void 0 : _f.call(_e); @@ -1436,8 +1705,9 @@ let Parser$1 = class Parser { if (this.cbs.onclosetag) { // Set the end index for all remaining tags this.endIndex = this.startIndex; - for (let i = this.stack.length; i > 0; this.cbs.onclosetag(this.stack[--i], true)) - ; + for (let index = 0; index < this.stack.length; index++) { + this.cbs.onclosetag(this.stack[index], true); + } } (_b = (_a = this.cbs).onend) === null || _b === void 0 ? void 0 : _b.call(_a); } @@ -1456,6 +1726,8 @@ let Parser$1 = class Parser { this.endIndex = 0; (_d = (_c = this.cbs).onparserinit) === null || _d === void 0 ? void 0 : _d.call(_c, this); this.buffers.length = 0; + this.foreignContext.length = 0; + this.foreignContext.unshift(!this.htmlMode); this.bufferOffset = 0; this.writeIndex = 0; this.ended = false; @@ -1474,12 +1746,12 @@ let Parser$1 = class Parser { while (start - this.bufferOffset >= this.buffers[0].length) { this.shiftBuffer(); } - let str = this.buffers[0].slice(start - this.bufferOffset, end - this.bufferOffset); + let slice = this.buffers[0].slice(start - this.bufferOffset, end - this.bufferOffset); while (end - this.bufferOffset > this.buffers[0].length) { this.shiftBuffer(); - str += this.buffers[0].slice(0, end - this.bufferOffset); + slice += this.buffers[0].slice(0, end - this.bufferOffset); } - return str; + return slice; } shiftBuffer() { this.bufferOffset += this.buffers[0].length; @@ -1511,7 +1783,7 @@ let Parser$1 = class Parser { end(chunk) { var _a, _b; if (this.ended) { - (_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, Error(".end() after done!")); + (_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, new Error(".end() after done!")); return; } if (chunk) @@ -2152,6 +2424,16 @@ function encodeXML(str) { } return ret + str.substr(lastIdx); } +/** + * Creates a function that escapes all characters matched by the given regular + * expression using the given map of characters to escape to their entities. + * + * @param regex Regular expression to match characters to escape. + * @param map Map of characters to escape to their entities. + * + * @returns Function that escapes all characters matched by the given regular + * expression using the given map of characters to escape to their entities. + */ function getEscaper(regex, map) { return function escape(data) { let match; @@ -2161,7 +2443,7 @@ function getEscaper(regex, map) { if (lastIdx !== match.index) { result += data.substring(lastIdx, match.index); } - // We know that this chararcter will be in the map. + // We know that this character will be in the map. result += map.get(match[0].charCodeAt(0)); // Every match will be of length 1 lastIdx = match.index + 1; @@ -2498,7 +2780,7 @@ function getInnerHTML(node, options) { : ""; } /** - * Get a node's inner text. Same as `textContent`, but inserts newlines for `<br>` tags. + * Get a node's inner text. Same as `textContent`, but inserts newlines for `<br>` tags. Ignores comments. * * @category Stringify * @deprecated Use `textContent` instead. @@ -2517,7 +2799,7 @@ function getText$1(node) { return ""; } /** - * Get a node's text content. + * Get a node's text content. Ignores comments. * * @category Stringify * @param node Node to get the text content of. @@ -2535,7 +2817,7 @@ function textContent(node) { return ""; } /** - * Get a node's inner text. + * Get a node's inner text, ignoring `<script>` and `<style>` tags. Ignores comments. * * @category Stringify * @param node Node to get the inner text of. @@ -2568,7 +2850,7 @@ function getChildren$1(elem) { * * @category Traversal * @param elem Node to get the parent of. - * @returns `elem`'s parent node. + * @returns `elem`'s parent node, or `null` if `elem` is a root node. */ function getParent$1(elem) { return elem.parent || null; @@ -2582,7 +2864,7 @@ function getParent$1(elem) { * * @category Traversal * @param elem Element to get the siblings of. - * @returns `elem`'s siblings. + * @returns `elem`'s siblings, including `elem`. */ function getSiblings$1(elem) { const parent = getParent$1(elem); @@ -2640,7 +2922,8 @@ function getName$1(elem) { * * @category Traversal * @param elem The element to get the next sibling of. - * @returns `elem`'s next sibling that is a tag. + * @returns `elem`'s next sibling that is a tag, or `null` if there is no next + * sibling. */ function nextElementSibling$1(elem) { let { next } = elem; @@ -2653,7 +2936,8 @@ function nextElementSibling$1(elem) { * * @category Traversal * @param elem The element to get the previous sibling of. - * @returns `elem`'s previous sibling that is a tag. + * @returns `elem`'s previous sibling that is a tag, or `null` if there is no + * previous sibling. */ function prevElementSibling(elem) { let { prev } = elem; @@ -2675,8 +2959,14 @@ function removeElement(elem) { elem.next.prev = elem.prev; if (elem.parent) { const childs = elem.parent.children; - childs.splice(childs.lastIndexOf(elem), 1); + const childsIndex = childs.lastIndexOf(elem); + if (childsIndex >= 0) { + childs.splice(childsIndex, 1); + } } + elem.next = null; + elem.prev = null; + elem.parent = null; } /** * Replace an element in the dom @@ -2705,15 +2995,15 @@ function replaceElement(elem, replacement) { * Append a child to an element. * * @category Manipulation - * @param elem The element to append to. + * @param parent The element to append to. * @param child The element to be added as a child. */ -function appendChild(elem, child) { +function appendChild(parent, child) { removeElement(child); child.next = null; - child.parent = elem; - if (elem.children.push(child) > 1) { - const sibling = elem.children[elem.children.length - 2]; + child.parent = parent; + if (parent.children.push(child) > 1) { + const sibling = parent.children[parent.children.length - 2]; sibling.next = child; child.prev = sibling; } @@ -2751,15 +3041,15 @@ function append$2(elem, next) { * Prepend a child to an element. * * @category Manipulation - * @param elem The element to prepend before. + * @param parent The element to prepend before. * @param child The element to be added as a child. */ -function prependChild(elem, child) { +function prependChild(parent, child) { removeElement(child); - child.parent = elem; + child.parent = parent; child.prev = null; - if (elem.children.unshift(child) !== 1) { - const sibling = elem.children[1]; + if (parent.children.unshift(child) !== 1) { + const sibling = parent.children[1]; sibling.prev = child; child.next = sibling; } @@ -2791,7 +3081,7 @@ function prepend(elem, prev) { } /** - * Search a node and its children for nodes passing a test function. + * Search a node and its children for nodes passing a test function. If `node` is not an array, it will be wrapped in one. * * @category Querying * @param test Function to test nodes on. @@ -2801,12 +3091,10 @@ function prepend(elem, prev) { * @returns All nodes passing `test`. */ function filter(test, node, recurse = true, limit = Infinity) { - if (!Array.isArray(node)) - node = [node]; - return find(test, node, recurse, limit); + return find(test, Array.isArray(node) ? node : [node], recurse, limit); } /** - * Search an array of node and its children for nodes passing a test function. + * Search an array of nodes and their children for nodes passing a test function. * * @category Querying * @param test Function to test nodes on. @@ -2817,24 +3105,41 @@ function filter(test, node, recurse = true, limit = Infinity) { */ function find(test, nodes, recurse, limit) { const result = []; - for (const elem of nodes) { + /** Stack of the arrays we are looking at. */ + const nodeStack = [nodes]; + /** Stack of the indices within the arrays. */ + const indexStack = [0]; + for (;;) { + // First, check if the current array has any more elements to look at. + if (indexStack[0] >= nodeStack[0].length) { + // If we have no more arrays to look at, we are done. + if (indexStack.length === 1) { + return result; + } + // Otherwise, remove the current array from the stack. + nodeStack.shift(); + indexStack.shift(); + // Loop back to the start to continue with the next array. + continue; + } + const elem = nodeStack[0][indexStack[0]++]; if (test(elem)) { result.push(elem); if (--limit <= 0) - break; + return result; } if (recurse && hasChildren(elem) && elem.children.length > 0) { - const children = find(test, elem.children, recurse, limit); - result.push(...children); - limit -= children.length; - if (limit <= 0) - break; + /* + * Add the children to the stack. We are depth-first, so this is + * the next array we look at. + */ + indexStack.unshift(0); + nodeStack.unshift(elem.children); } } - return result; } /** - * Finds the first element inside of an array that matches a test function. + * Finds the first element inside of an array that matches a test function. This is an alias for `Array.prototype.find`. * * @category Querying * @param test Function to test nodes on. @@ -2850,27 +3155,29 @@ function findOneChild(test, nodes) { * * @category Querying * @param test Function to test nodes on. - * @param nodes Array of nodes to search. + * @param nodes Node or array of nodes to search. * @param recurse Also consider child nodes. - * @returns The first child node that passes `test`. + * @returns The first node that passes `test`. */ function findOne$1(test, nodes, recurse = true) { let elem = null; for (let i = 0; i < nodes.length && !elem; i++) { - const checked = nodes[i]; - if (!isTag$1(checked)) { + const node = nodes[i]; + if (!isTag$1(node)) { continue; } - else if (test(checked)) { - elem = checked; + else if (test(node)) { + elem = node; } - else if (recurse && checked.children.length > 0) { - elem = findOne$1(test, checked.children, true); + else if (recurse && node.children.length > 0) { + elem = findOne$1(test, node.children, true); } } return elem; } /** + * Checks if a tree of nodes contains at least one node passing a test. + * * @category Querying * @param test Function to test nodes on. * @param nodes Array of nodes to search. @@ -2878,12 +3185,10 @@ function findOne$1(test, nodes, recurse = true) { */ function existsOne$1(test, nodes) { return nodes.some((checked) => isTag$1(checked) && - (test(checked) || - (checked.children.length > 0 && - existsOne$1(test, checked.children)))); + (test(checked) || existsOne$1(test, checked.children))); } /** - * Search and array of nodes and its children for elements passing a test function. + * Search an array of nodes and their children for elements passing a test function. * * Same as `find`, but limited to elements and with less options, leading to reduced complexity. * @@ -2893,21 +3198,35 @@ function existsOne$1(test, nodes) { * @returns All nodes passing `test`. */ function findAll$1(test, nodes) { - var _a; const result = []; - const stack = nodes.filter(isTag$1); - let elem; - while ((elem = stack.shift())) { - const children = (_a = elem.children) === null || _a === void 0 ? void 0 : _a.filter(isTag$1); - if (children && children.length > 0) { - stack.unshift(...children); + const nodeStack = [nodes]; + const indexStack = [0]; + for (;;) { + if (indexStack[0] >= nodeStack[0].length) { + if (nodeStack.length === 1) { + return result; + } + // Otherwise, remove the current array from the stack. + nodeStack.shift(); + indexStack.shift(); + // Loop back to the start to continue with the next array. + continue; } + const elem = nodeStack[0][indexStack[0]++]; + if (!isTag$1(elem)) + continue; if (test(elem)) result.push(elem); + if (elem.children.length > 0) { + indexStack.unshift(0); + nodeStack.unshift(elem.children); + } } - return result; } +/** + * A map of functions to check nodes against. + */ const Checks = { tag_name(name) { if (typeof name === "function") { @@ -2932,6 +3251,9 @@ const Checks = { }, }; /** + * Returns a function to check whether a node has an attribute with a particular + * value. + * * @param attrib Attribute to check. * @param value Attribute value to look for. * @returns A function to check whether the a node has an attribute with a @@ -2944,6 +3266,9 @@ function getAttribCheck(attrib, value) { return (elem) => isTag$1(elem) && elem.attribs[attrib] === value; } /** + * Returns a function that returns `true` if either of the input functions + * returns `true` for a node. + * * @param a First function to combine. * @param b Second function to combine. * @returns A function taking a node and returning `true` if either of the input @@ -2953,9 +3278,12 @@ function combineFuncs(a, b) { return (elem) => a(elem) || b(elem); } /** + * Returns a function that executes all checks in `options` and returns `true` + * if any of them match a node. + * * @param options An object describing nodes to look for. - * @returns A function executing all checks in `options` and returning `true` if - * any of them match a node. + * @returns A function that executes all checks in `options` and returns `true` + * if any of them match a node. */ function compileTest(options) { const funcs = Object.keys(options).map((key) => { @@ -2967,6 +3295,8 @@ function compileTest(options) { return funcs.length === 0 ? null : funcs.reduce(combineFuncs); } /** + * Checks whether a node matches the description in `options`. + * * @category Legacy Query Functions * @param options An object describing nodes to look for. * @param node The element to test. @@ -2977,6 +3307,8 @@ function testElement(options, node) { return test ? test(node) : true; } /** + * Returns all nodes that match `options`. + * * @category Legacy Query Functions * @param options An object describing nodes to look for. * @param nodes Nodes to search through. @@ -2989,6 +3321,8 @@ function getElements(options, nodes, recurse, limit = Infinity) { return test ? filter(test, nodes, recurse, limit) : []; } /** + * Returns the node with the supplied ID. + * * @category Legacy Query Functions * @param id The unique ID attribute value to look for. * @param nodes Nodes to search through. @@ -3001,6 +3335,8 @@ function getElementById(id, nodes, recurse = true) { return findOne$1(getAttribCheck("id", id), nodes, recurse); } /** + * Returns all nodes with the supplied `tagName`. + * * @category Legacy Query Functions * @param tagName Tag name to search for. * @param nodes Nodes to search through. @@ -3012,6 +3348,8 @@ function getElementsByTagName(tagName, nodes, recurse = true, limit = Infinity) return filter(Checks["tag_name"](tagName), nodes, recurse, limit); } /** + * Returns all nodes with the supplied `type`. + * * @category Legacy Query Functions * @param type Element type to look for. * @param nodes Nodes to search through. @@ -3024,11 +3362,12 @@ function getElementsByTagType(type, nodes, recurse = true, limit = Infinity) { } /** - * Given an array of nodes, remove any member that is contained by another. + * Given an array of nodes, remove any member that is contained by another + * member. * * @category Helpers * @param nodes Nodes to filter. - * @returns Remaining nodes that aren't subtrees of each other. + * @returns Remaining nodes that aren't contained by other nodes. */ function removeSubsets$1(nodes) { let idx = nodes.length; @@ -3069,8 +3408,8 @@ var DocumentPosition; DocumentPosition[DocumentPosition["CONTAINED_BY"] = 16] = "CONTAINED_BY"; })(DocumentPosition || (DocumentPosition = {})); /** - * Compare the position of one node against another node in any other document. - * The return value is a bitmask with the values from {@link DocumentPosition}. + * Compare the position of one node against another node in any other document, + * returning a bitmask with the values from {@link DocumentPosition}. * * Document order: * > There is an ordering, document order, defined on all the nodes in the @@ -3134,9 +3473,9 @@ function compareDocumentPosition(nodeA, nodeB) { return DocumentPosition.PRECEDING; } /** - * Sort an array of nodes based on their relative position in the document and - * remove any duplicate nodes. If the array contains nodes that do not belong to - * the same document, sort order is unspecified. + * Sort an array of nodes based on their relative position in the document, + * removing any duplicate nodes. If the array contains nodes that do not belong + * to the same document, sort order is unspecified. * * @category Helpers * @param nodes Array of DOM nodes. @@ -3237,7 +3576,7 @@ function getRssFeed(feedRoot) { addConditionally(entry, "title", "title", children); addConditionally(entry, "link", "link", children); addConditionally(entry, "description", "description", children); - const pubDate = fetch("pubDate", children); + const pubDate = fetch("pubDate", children) || fetch("dc:date", children); if (pubDate) entry.pubDate = new Date(pubDate); return entry; @@ -3388,7 +3727,7 @@ var DomUtils = /*#__PURE__*/Object.freeze({ * Parses the data, returns the resulting document. * * @param data The data that should be parsed. - * @param options Optional options for the parser and DOM builder. + * @param options Optional options for the parser and DOM handler. */ function parseDocument(data, options) { const handler = new DomHandler(undefined, options); @@ -3402,7 +3741,7 @@ function parseDocument(data, options) { * Use `parseDocument` to get the `Document` node instead. * * @param data The data that should be parsed. - * @param options Optional options for the parser and DOM builder. + * @param options Optional options for the parser and DOM handler. * @deprecated Use `parseDocument` instead. */ function parseDOM(data, options) { @@ -3411,21 +3750,34 @@ function parseDOM(data, options) { /** * Creates a parser instance, with an attached DOM handler. * - * @param cb A callback that will be called once parsing has been completed. - * @param options Optional options for the parser and DOM builder. - * @param elementCb An optional callback that will be called every time a tag has been completed inside of the DOM. + * @param callback A callback that will be called once parsing has been completed, with the resulting document. + * @param options Optional options for the parser and DOM handler. + * @param elementCallback An optional callback that will be called every time a tag has been completed inside of the DOM. */ -function createDomStream(cb, options, elementCb) { - const handler = new DomHandler(cb, options, elementCb); +function createDocumentStream(callback, options, elementCallback) { + const handler = new DomHandler((error) => callback(error, handler.root), options, elementCallback); return new Parser$1(handler, options); } +/** + * Creates a parser instance, with an attached DOM handler. + * + * @param callback A callback that will be called once parsing has been completed, with an array of root nodes. + * @param options Optional options for the parser and DOM handler. + * @param elementCallback An optional callback that will be called every time a tag has been completed inside of the DOM. + * @deprecated Use `createDocumentStream` instead. + */ +function createDomStream(callback, options, elementCallback) { + const handler = new DomHandler(callback, options, elementCallback); + return new Parser$1(handler, options); +} +const parseFeedDefaultOptions = { xmlMode: true }; /** * Parse a feed. * * @param feed The feed that should be parsed, as a string. * @param options Optionally, options for parsing. When using this, you should set `xmlMode` to `true`. */ -function parseFeed(feed, options = { xmlMode: true }) { +function parseFeed(feed, options = parseFeedDefaultOptions) { return getFeed(parseDOM(feed, options)); } @@ -3437,6 +3789,7 @@ var HTMLParser2 = /*#__PURE__*/Object.freeze({ ElementType: index, Parser: Parser$1, Tokenizer: Tokenizer, + createDocumentStream: createDocumentStream, createDomStream: createDomStream, getFeed: getFeed, parseDOM: parseDOM, @@ -3714,6 +4067,18 @@ class CustomElementRegistry { const info = this.registry.get(localName); return info && info.Class; } + + /** + * @param {Function} Class **Class** of custom element + * @returns {string?} found tag name or null + */ + getName(Class) { + if (Classes.has(Class)) { + const { localName } = Classes.get(Class); + return localName; + } + return null; + } } const {Parser} = HTMLParser2; @@ -4254,6 +4619,7 @@ class NodeList extends Array { // https://dom.spec.whatwg.org/#node + const getParentNodeCount = ({parentNode}) => { let count = 0; while (parentNode) { @@ -4466,8 +4832,8 @@ let Attr$1 = class Attr extends Node$1 { toString() { const {name, [VALUE]: value} = this; - return emptyAttributes.has(name) && !value ? - name : `${name}="${value.replace(QUOTE, '"')}"`; + return emptyAttributes.has(name) && !value && ignoreCase(this) ? + name : `${name}="${value.replace(QUOTE, '"')}"`; } toJSON() { @@ -4515,6 +4881,8 @@ const nextSibling = node => { }; // https://dom.spec.whatwg.org/#nondocumenttypechildnode +// CharacterData, Element + const nextElementSibling = node => { let next = nextSibling(node); @@ -4531,6 +4899,8 @@ const previousElementSibling = node => { }; // https://dom.spec.whatwg.org/#childnode +// CharacterData, DocumentType, Element + const asFragment = (ownerDocument, nodes) => { const fragment = ownerDocument.createDocumentFragment(); @@ -4559,6 +4929,8 @@ const after = (node, nodes) => { const replaceWith = (node, nodes) => { const {ownerDocument, parentNode} = node; if (parentNode) { + if (nodes.includes(node)) + replaceWith(node, [node = node.cloneNode()]); parentNode.insertBefore( asFragment(ownerDocument, nodes), node @@ -4584,6 +4956,7 @@ const remove = (prev, current, next) => { // https://dom.spec.whatwg.org/#interface-characterdata + /** * @implements globalThis.CharacterData */ @@ -4688,6 +5061,10 @@ let Comment$1 = class Comment extends CharacterData$1 { toString() { return `<!--${this[VALUE]}-->`; } }; +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + var boolbase = { trueFunc: function trueFunc(){ return true; @@ -4697,6 +5074,8 @@ var boolbase = { } }; +var boolbase$1 = /*@__PURE__*/getDefaultExportFromCjs(boolbase); + var SelectorType; (function (SelectorType) { SelectorType["Attribute"] = "attribute"; @@ -5340,7 +5719,7 @@ const attributeRules = { const { adapter } = options; const { name, value } = data; if (/\s/.test(value)) { - return boolbase.falseFunc; + return boolbase$1.falseFunc; } const regex = new RegExp(`(?:^|\\s)${escapeRegex(value)}(?:$|\\s)`, shouldIgnoreCase(data, options) ? "i" : ""); return function element(elem) { @@ -5360,7 +5739,7 @@ const attributeRules = { let { value } = data; const len = value.length; if (len === 0) { - return boolbase.falseFunc; + return boolbase$1.falseFunc; } if (shouldIgnoreCase(data, options)) { value = value.toLowerCase(); @@ -5384,7 +5763,7 @@ const attributeRules = { let { value } = data; const len = -value.length; if (len === 0) { - return boolbase.falseFunc; + return boolbase$1.falseFunc; } if (shouldIgnoreCase(data, options)) { value = value.toLowerCase(); @@ -5404,7 +5783,7 @@ const attributeRules = { const { adapter } = options; const { name, value } = data; if (value === "") { - return boolbase.falseFunc; + return boolbase$1.falseFunc; } if (shouldIgnoreCase(data, options)) { const regex = new RegExp(escapeRegex(value), "i"); @@ -5548,7 +5927,7 @@ function compile$2(parsed) { * `b < 0` here as we subtracted 1 from `b` above. */ if (b < 0 && a <= 0) - return boolbase.falseFunc; + return boolbase$1.falseFunc; // When `a` is in the range -1..1, it matches any element (so only `b` is checked). if (a === -1) return (index) => index <= b; @@ -5556,7 +5935,7 @@ function compile$2(parsed) { return (index) => index === b; // When `b <= 0` and `a === 1`, they match any element. if (a === 1) - return b < 0 ? boolbase.trueFunc : (index) => index >= b; + return b < 0 ? boolbase$1.trueFunc : (index) => index >= b; /* * Otherwise, modulo can be used to check if there is a match. * @@ -5619,9 +5998,9 @@ const filters = { // Location specific methods "nth-child"(next, rule, { adapter, equals }) { const func = nthCheck(rule); - if (func === boolbase.falseFunc) - return boolbase.falseFunc; - if (func === boolbase.trueFunc) + if (func === boolbase$1.falseFunc) + return boolbase$1.falseFunc; + if (func === boolbase$1.trueFunc) return getChildFunc(next, adapter); return function nthChild(elem) { const siblings = adapter.getSiblings(elem); @@ -5638,9 +6017,9 @@ const filters = { }, "nth-last-child"(next, rule, { adapter, equals }) { const func = nthCheck(rule); - if (func === boolbase.falseFunc) - return boolbase.falseFunc; - if (func === boolbase.trueFunc) + if (func === boolbase$1.falseFunc) + return boolbase$1.falseFunc; + if (func === boolbase$1.trueFunc) return getChildFunc(next, adapter); return function nthLastChild(elem) { const siblings = adapter.getSiblings(elem); @@ -5657,9 +6036,9 @@ const filters = { }, "nth-of-type"(next, rule, { adapter, equals }) { const func = nthCheck(rule); - if (func === boolbase.falseFunc) - return boolbase.falseFunc; - if (func === boolbase.trueFunc) + if (func === boolbase$1.falseFunc) + return boolbase$1.falseFunc; + if (func === boolbase$1.trueFunc) return getChildFunc(next, adapter); return function nthOfType(elem) { const siblings = adapter.getSiblings(elem); @@ -5678,9 +6057,9 @@ const filters = { }, "nth-last-of-type"(next, rule, { adapter, equals }) { const func = nthCheck(rule); - if (func === boolbase.falseFunc) - return boolbase.falseFunc; - if (func === boolbase.trueFunc) + if (func === boolbase$1.falseFunc) + return boolbase$1.falseFunc; + if (func === boolbase$1.trueFunc) return getChildFunc(next, adapter); return function nthLastOfType(elem) { const siblings = adapter.getSiblings(elem); @@ -5730,7 +6109,7 @@ function dynamicStatePseudo(name) { return function dynamicPseudo(next, _rule, { adapter }) { const func = adapter[name]; if (typeof func !== "function") { - return boolbase.falseFunc; + return boolbase$1.falseFunc; } return function active(elem) { return func(elem) && next(elem); @@ -5855,8 +6234,8 @@ const aliases = { /** Used as a placeholder for :has. Will be replaced with the actual element. */ const PLACEHOLDER_ELEMENT = {}; function ensureIsTag(next, adapter) { - if (next === boolbase.falseFunc) - return boolbase.falseFunc; + if (next === boolbase$1.falseFunc) + return boolbase$1.falseFunc; return (elem) => adapter.isTag(elem) && next(elem); } function getNextSiblings(elem, adapter) { @@ -5883,10 +6262,10 @@ function copyOptions(options) { } const is$1 = (next, token, options, context, compileToken) => { const func = compileToken(token, copyOptions(options), context); - return func === boolbase.trueFunc + return func === boolbase$1.trueFunc ? next - : func === boolbase.falseFunc - ? boolbase.falseFunc + : func === boolbase$1.falseFunc + ? boolbase$1.falseFunc : (elem) => func(elem) && next(elem); }; /* @@ -5903,10 +6282,10 @@ const subselects = { where: is$1, not(next, token, options, context, compileToken) { const func = compileToken(token, copyOptions(options), context); - return func === boolbase.falseFunc + return func === boolbase$1.falseFunc ? next - : func === boolbase.trueFunc - ? boolbase.falseFunc + : func === boolbase$1.trueFunc + ? boolbase$1.falseFunc : (elem) => !func(elem) && next(elem); }, has(next, subselect, options, _context, compileToken) { @@ -5918,11 +6297,11 @@ const subselects = { [PLACEHOLDER_ELEMENT] : undefined; const compiled = compileToken(subselect, opts, context); - if (compiled === boolbase.falseFunc) - return boolbase.falseFunc; + if (compiled === boolbase$1.falseFunc) + return boolbase$1.falseFunc; const hasElement = ensureIsTag(compiled, adapter); // If `compiled` is `trueFunc`, we can skip this. - if (context && compiled !== boolbase.trueFunc) { + if (context && compiled !== boolbase$1.trueFunc) { /* * `shouldTestNextSiblings` will only be true if the query starts with * a traversal (sibling or adjacent). That means we will always have a context. @@ -6203,21 +6582,21 @@ function compileToken(token, options, context) { } return compileRules(rules, options, finalContext); }) - .reduce(reduceRules, boolbase.falseFunc); + .reduce(reduceRules, boolbase$1.falseFunc); query.shouldTestNextSiblings = shouldTestNextSiblings; return query; } function compileRules(rules, options, context) { var _a; - return rules.reduce((previous, rule) => previous === boolbase.falseFunc - ? boolbase.falseFunc - : compileGeneralSelector(previous, rule, options, context, compileToken), (_a = options.rootFunc) !== null && _a !== void 0 ? _a : boolbase.trueFunc); + return rules.reduce((previous, rule) => previous === boolbase$1.falseFunc + ? boolbase$1.falseFunc + : compileGeneralSelector(previous, rule, options, context, compileToken), (_a = options.rootFunc) !== null && _a !== void 0 ? _a : boolbase$1.trueFunc); } function reduceRules(a, b) { - if (b === boolbase.falseFunc || a === boolbase.trueFunc) { + if (b === boolbase$1.falseFunc || a === boolbase$1.trueFunc) { return a; } - if (a === boolbase.falseFunc || b === boolbase.trueFunc) { + if (a === boolbase$1.falseFunc || b === boolbase$1.trueFunc) { return b; } return function combine(elem) { @@ -6444,6 +6823,8 @@ let Text$1 = class Text extends CharacterData$1 { }; // https://dom.spec.whatwg.org/#interface-parentnode +// Document, DocumentFragment, Element + const isNode = node => node instanceof Node$1; @@ -6712,6 +7093,8 @@ class ParentNode extends Node$1 { } // https://dom.spec.whatwg.org/#interface-nonelementparentnode +// Document, DocumentFragment + class NonElementParentNode extends ParentNode { getElementById(id) { @@ -7102,6 +7485,10 @@ const AT_TARGET = 2; const CAPTURING_PHASE = 1; const NONE = 0; +function getCurrentTarget(ev) { + return ev.currentTarget; +} + /** * @implements globalThis.Event */ @@ -7136,7 +7523,7 @@ class GlobalEvent { // simplified implementation, should be https://dom.spec.whatwg.org/#dom-event-composedpath composedPath() { - return this._path; + return this._path.map(getCurrentTarget); } stopPropagation() { @@ -7213,6 +7600,7 @@ let ShadowRoot$1 = class ShadowRoot extends NonElementParentNode { // https://dom.spec.whatwg.org/#interface-element + // <utils> const attributesHandler = { get(target, key) { @@ -7354,7 +7742,7 @@ let Element$1 = class Element extends ParentNode { set textContent(text) { this.replaceChildren(); - if (text != null) + if (text != null && text !== '') this.appendChild(new Text$1(this.ownerDocument, text)); } @@ -7859,7 +8247,12 @@ class HTMLElement extends Element$1 { */ blur() { this.dispatchEvent(new GlobalEvent('blur')); } - click() { this.dispatchEvent(new GlobalEvent('click')); } + click() { + const clickEvent = new GlobalEvent('click', {bubbles: true, cancelable: true}); + clickEvent.button = 0; + + this.dispatchEvent(clickEvent); + } // Boolean getters get accessKeyLabel() { @@ -11357,6 +11750,7 @@ const Mime = { // https://dom.spec.whatwg.org/#interface-customevent + /** * @implements globalThis.CustomEvent */ @@ -11371,6 +11765,7 @@ class CustomEvent extends GlobalEvent { // https://dom.spec.whatwg.org/#interface-customevent + /** * @implements globalThis.InputEvent */ @@ -11408,6 +11803,7 @@ class Image extends HTMLImageElement { // https://dom.spec.whatwg.org/#concept-live-range + const deleteContents = ({[START]: start, [END]: end}, fragment = null) => { setAdjacent(start[PREV], end[NEXT]); do { @@ -11732,6 +12128,8 @@ let Document$1 = class Document extends NonElementParentNode { cancelable = false, detail ) => { + event.bubbles = !!canBubble; + defineProperties(event, { type: {value: type}, canBubble: {value: canBubble}, diff --git a/src/popup/style.css b/src/popup/style.css index 2b3adea2..1219b50a 100644 --- a/src/popup/style.css +++ b/src/popup/style.css @@ -219,16 +219,6 @@ dialog { scrollbar-width: thin; width: 100vw; } -/* Utiliser des pseudo-éléments spécifiques, car la propriété scrollbar-width - n'est pas implémentée dans Chromium. https://crbug.com/891944 */ -#playlist-items::-webkit-scrollbar { - background-color: black; - width: 5px; -} -#playlist-items::-webkit-scrollbar-thumb { - background-color: var(--range-track-background-color); - border-radius: 2.5px; -} #playlist-items ol { display: flex; diff --git a/test/unit/core/labeller/plugin/vtmgo.js b/test/unit/core/labeller/plugin/vtmgo.js index 81d28a0b..2c6a9550 100644 --- a/test/unit/core/labeller/plugin/vtmgo.js +++ b/test/unit/core/labeller/plugin/vtmgo.js @@ -28,11 +28,11 @@ describe("core/labeller/plugin/vtmgo.js", function () { ]); }); - it("should return label in Firefox", async function () { + it("should return label in Chromium", async function () { const fake = sinon.fake.resolves("foo"); - // Simuler un mauvais découpage d'une URL par Firefox. - // https://bugzil.la/1374505 + // Simuler un mauvais découpage d'une URL par Chromium. + // https://crbug.com/1416006 const url = { href: "plugin://plugin.video.vtm.go/play/catalog/episodes/bar", pathname: "//plugin.video.vtm.go/play/catalog/episodes/bar", @@ -69,11 +69,11 @@ describe("core/labeller/plugin/vtmgo.js", function () { ]); }); - it("should return label in Firefox", async function () { + it("should return label in Chromium", async function () { const fake = sinon.fake.resolves("foo"); - // Simuler un mauvais découpage d'une URL par Firefox. - // https://bugzil.la/1374505 + // Simuler un mauvais découpage d'une URL par Chromium. + // https://crbug.com/1416006 const url = { href: "plugin://plugin.video.vtm.go/play/catalog/movies/bar", pathname: "//plugin.video.vtm.go/play/catalog/movies/bar", diff --git a/test/unit/core/scraper/ldjson.js b/test/unit/core/scraper/ldjson.js index 7625e03e..18837264 100644 --- a/test/unit/core/scraper/ldjson.js +++ b/test/unit/core/scraper/ldjson.js @@ -246,5 +246,34 @@ describe("core/scraper/ldjson.js", function () { const file = await scraper.extract(url, metadata, context); assert.equal(file, undefined); }); + + it("should ignore incomplete node", async function () { + const url = new URL("http://foo.com"); + const metadata = { + html: () => + Promise.resolve( + new DOMParser().parseFromString( + ` + <html><body> + <script type="application/ld+json">${JSON.stringify({ + "@context": "http://schema.org/", + // Le nœud MusicVideoObject devrait avoir un + // "contentUrl" ou un "embedUrl". + "@type": "MusicVideoObject", + clip: { + "@type": "VideoObject", + contentUrl: "https://bar.com/baz.mp4", + }, + })}</script> + </body></html>`, + "text/html", + ), + ), + }; + const context = { depth: false }; + + const file = await scraper.extract(url, metadata, context); + assert.equal(file, "https://bar.com/baz.mp4"); + }); }); });