From 4f270a5da98439100ee432428504a969357eca69 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Thu, 8 Aug 2024 14:05:39 -0400 Subject: [PATCH 01/24] Tell users when a template causes build invalidation (#12746) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- sphinx/builders/html/__init__.py | 19 ++++++++++++++++++- sphinx/jinja2glue.py | 8 +++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index 06917232f6b..8f351b76a12 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -40,6 +40,7 @@ from sphinx.theming import HTMLThemeFactory from sphinx.util import isurl, logging from sphinx.util._timestamps import _format_rfc3339_microseconds +from sphinx.util.console import bold from sphinx.util.display import progress_message, status_iterator from sphinx.util.docutils import new_document from sphinx.util.fileutil import copy_asset @@ -389,8 +390,9 @@ def math_renderer_name(self) -> str | None: return None def get_outdated_docs(self) -> Iterator[str]: + build_info_fname = self.outdir / '.buildinfo' try: - with open(path.join(self.outdir, '.buildinfo'), encoding="utf-8") as fp: + with open(build_info_fname, encoding="utf-8") as fp: buildinfo = BuildInfo.load(fp) if self.build_info != buildinfo: @@ -405,6 +407,21 @@ def get_outdated_docs(self) -> Iterator[str]: if self.templates: template_mtime = int(self.templates.newest_template_mtime() * 10**6) + try: + old_mtime = _last_modified_time(build_info_fname) + except Exception: + pass + else: + # Let users know they have a newer template + if template_mtime > old_mtime: + logger.info( + bold("building [html]: ") + + __( + "template %s has been changed since the previous build, " + "all docs will be rebuilt" + ), + self.templates.newest_template_name(), + ) else: template_mtime = 0 for docname in self.env.found_docs: diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index ec75c6d96cb..74321383455 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -204,8 +204,14 @@ def render_string(self, source: str, context: dict) -> str: return self.environment.from_string(source).render(context) def newest_template_mtime(self) -> float: + return self._newest_template_mtime_name()[0] + + def newest_template_name(self) -> str: + return self._newest_template_mtime_name()[1] + + def _newest_template_mtime_name(self) -> tuple[float, str]: return max( - os.stat(os.path.join(root, sfile)).st_mtime_ns / 10**9 + (os.stat(os.path.join(root, sfile)).st_mtime_ns / 10**9, sfile) for dirname in self.pathchain for root, _dirs, files in os.walk(dirname) for sfile in files From d40840ebf142aeece525ae049021736999fa0cae Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:22:12 +0200 Subject: [PATCH 02/24] Slightly simplify toctree code (#12724) --- sphinx/directives/other.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index f74f919cc3e..b9e2586adeb 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -78,17 +78,19 @@ def run(self) -> list[Node]: subnode['numbered'] = self.options.get('numbered', 0) subnode['titlesonly'] = 'titlesonly' in self.options self.set_source_info(subnode) + self.parse_content(subnode) + wrappernode = nodes.compound( classes=['toctree-wrapper', *self.options.get('class', ())], ) wrappernode.append(subnode) self.add_name(wrappernode) + return [wrappernode] - ret = self.parse_content(subnode) - ret.append(wrappernode) - return ret - - def parse_content(self, toctree: addnodes.toctree) -> list[Node]: + def parse_content(self, toctree: addnodes.toctree) -> None: + """ + Populate ``toctree['entries']`` and ``toctree['includefiles']`` from content. + """ generated_docnames = frozenset(StandardDomain._virtual_doc_names) suffixes = self.config.source_suffix current_docname = self.env.docname @@ -99,7 +101,6 @@ def parse_content(self, toctree: addnodes.toctree) -> list[Node]: all_docnames.remove(current_docname) # remove current document frozen_all_docnames = frozenset(all_docnames) - ret: list[Node] = [] excluded = Matcher(self.config.exclude_patterns) for entry in self.content: if not entry: @@ -170,8 +171,6 @@ def parse_content(self, toctree: addnodes.toctree) -> list[Node]: toctree['entries'] = list(reversed(toctree['entries'])) toctree['includefiles'] = list(reversed(toctree['includefiles'])) - return ret - class Author(SphinxDirective): """ From 96b511798da0ab819b87be363fe505186896fee2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:22:35 +0100 Subject: [PATCH 03/24] Bump Ruff to 0.5.7 (#12750) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1f45185dc24..752769377d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,7 +81,7 @@ docs = [ ] lint = [ "flake8>=6.0", - "ruff==0.5.5", + "ruff==0.5.7", "mypy==1.11.1", "sphinx-lint>=0.9", "types-colorama==0.4.15.20240311", From e3238260f6e2fddfb71a38acd44511307c5c5d2f Mon Sep 17 00:00:00 2001 From: James Addison <55152140+jayaddison@users.noreply.github.com> Date: Sat, 10 Aug 2024 00:18:27 +0100 Subject: [PATCH 04/24] Migrate JavaScript tests from Karma to the Jasmine framework (#12754) --- .github/workflows/nodejs.yml | 2 - CHANGES.rst | 4 + doc/internals/contributing.rst | 13 +- karma.conf.js | 75 - package-lock.json | 2863 ++++++++++++++------------------ package.json | 8 +- tests/js/jasmine-browser.mjs | 29 + tests/js/searchtools.js | 2 +- 8 files changed, 1305 insertions(+), 1691 deletions(-) delete mode 100644 karma.conf.js create mode 100644 tests/js/jasmine-browser.mjs diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index b7f6f21bd8d..fece8861873 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -6,7 +6,6 @@ on: - ".github/workflows/nodejs.yml" - "sphinx/themes/**.js" - "tests/js/**" - - "karma.conf.js" - "package.json" - "package-lock.json" pull_request: @@ -14,7 +13,6 @@ on: - ".github/workflows/nodejs.yml" - "sphinx/themes/**.js" - "tests/js/**" - - "karma.conf.js" - "package.json" - "package-lock.json" diff --git a/CHANGES.rst b/CHANGES.rst index 4b920ca3911..c629a6d9a55 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -28,3 +28,7 @@ Bugs fixed Testing ------- + +* #12141: Migrate from the deprecated ``karma`` JavaScript test framework to + the actively-maintained ``jasmine`` framework. Test coverage is unaffected. + Patch by James Addison. diff --git a/doc/internals/contributing.rst b/doc/internals/contributing.rst index e2981c0a1e6..0f387341658 100644 --- a/doc/internals/contributing.rst +++ b/doc/internals/contributing.rst @@ -174,10 +174,10 @@ Style and type checks can be run as follows: Unit tests ~~~~~~~~~~ -Sphinx is tested using pytest_ for Python code and Karma_ for JavaScript. +Sphinx is tested using pytest_ for Python code and Jasmine_ for JavaScript. .. _pytest: https://docs.pytest.org/en/latest/ -.. _Karma: https://karma-runner.github.io +.. _Jasmine: https://jasmine.github.io/ To run Python unit tests, we recommend using :program:`tox`, which provides a number of targets and allows testing against multiple different Python environments: @@ -216,13 +216,10 @@ To run JavaScript tests, use :program:`npm`: .. tip:: - :program:`karma` requires a Firefox binary to use as a test browser. + :program:`jasmine` requires a Firefox binary to use as a test browser. - For Unix-based systems, you can specify the path to the Firefox binary using: - - .. code-block:: shell - - FIREFOX_BIN="/Applications/Firefox.app/Contents/MacOS/firefox" npm test + On Unix systems, you can check the presence and location of the ``firefox`` + binary at the command-line by running ``command -v firefox``. New unit tests should be included in the :file:`tests/` directory where necessary: diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index 4f1b9c616e4..00000000000 --- a/karma.conf.js +++ /dev/null @@ -1,75 +0,0 @@ -// Karma configuration -// Generated on Sat Jul 21 2018 22:01:48 GMT+0200 (CEST) - -module.exports = function(config) { - config.set({ - - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine'], - - - // list of files / patterns to load in the browser - files: [ - { pattern: 'tests/js/fixtures/**/*.js', included: false, served: true }, - 'tests/js/documentation_options.js', - 'tests/js/language_data.js', - 'sphinx/themes/basic/static/doctools.js', - 'sphinx/themes/basic/static/searchtools.js', - 'sphinx/themes/basic/static/sphinx_highlight.js', - 'tests/js/*.js' - ], - - - // list of files / patterns to exclude - exclude: [ - ], - - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - }, - - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], - - - // web server port - port: 9876, - - - // enable / disable colors in the output (reporters and logs) - colors: true, - - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ["Firefox"], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false, - - // Concurrency level - // how many browser should be started simultaneous - concurrency: Infinity - }) -} diff --git a/package-lock.json b/package-lock.json index 12c33c40a2f..3340f176ee8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,49 +6,120 @@ "": { "name": "sphinx", "devDependencies": { - "jasmine-core": "^3.4.0", - "karma": "^6.3.16", - "karma-firefox-launcher": "^2.0.0", - "karma-jasmine": "^4.0.0" + "jasmine-browser-runner": "^2.5.0", + "jasmine-core": "^5.2.0" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "node_modules/@bazel/runfiles": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-5.8.1.tgz", + "integrity": "sha512-NDdfpdQ6rZlylgv++iMn5FkObC/QlBQvipinGLSOguTYpRywmieOyJ29XHvUilspwTFSILWpoE9CqMGkHXug1g==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "engines": { - "node": ">=0.1.90" + "node": ">=12" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "dev": true + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { - "@types/node": "*" + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@types/node": { - "version": "20.11.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz", - "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" } }, "node_modules/accepts": { @@ -88,18 +159,17 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true }, "node_modules/balanced-match": { "version": "1.0.2", @@ -107,24 +177,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -171,18 +223,6 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -211,36 +251,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 8.10.0" + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/color-convert": { @@ -267,19 +291,16 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "safe-buffer": "5.2.1" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 0.6" } }, "node_modules/content-type": { @@ -291,41 +312,30 @@ "node": ">= 0.6" } }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">=4.0" + "node": ">= 8" } }, "node_modules/debug": { @@ -373,30 +383,33 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", - "dev": true, - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -412,65 +425,6 @@ "node": ">= 0.8" } }, - "node_modules/engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", - "dev": true, - "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/engine.io/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -492,121 +446,173 @@ "node": ">= 0.4" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, "dependencies": { - "to-regex-range": "^5.0.1" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.10.0" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], "engines": { - "node": ">=4.0" + "node": ">= 0.8" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "engines": { + "node": ">=10" } }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 0.6" } }, "node_modules/function-bind": { @@ -618,15 +624,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -646,38 +643,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -690,11 +655,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/has-property-descriptors": { "version": "1.0.2", @@ -769,41 +737,23 @@ "node": ">= 0.8" } }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true }, "node_modules/inherits": { "version": "2.0.4", @@ -811,40 +761,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, "engines": { - "node": ">=8" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, "node_modules/is-fullwidth-code-point": { @@ -856,178 +779,144 @@ "node": ">=8" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "dependencies": { - "is-extglob": "^2.1.1" + "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, "engines": { - "node": ">=0.12.0" + "node": ">=10" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/jasmine-browser-runner": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jasmine-browser-runner/-/jasmine-browser-runner-2.5.0.tgz", + "integrity": "sha512-CzdvpeZunUu6x1u8G6/vPnfcKVpDaBFfk3tIvm1hoA+EfceQ8FRvsy4o8hEcKYyMt556XFRnP5PjYsxFU8z7Xw==", "dev": true, "dependencies": { - "is-docker": "^2.0.0" + "ejs": "^3.1.6", + "express": "^4.19.2", + "glob": "^10.0.0", + "selenium-webdriver": "^4.12.0" }, - "engines": { - "node": ">=8" + "bin": { + "jasmine-browser-runner": "bin/jasmine-browser-runner" + }, + "peerDependencies": { + "jasmine-core": "^5.0.0" } }, - "node_modules/isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "node_modules/jasmine-browser-runner/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/jasmine-core": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.10.1.tgz", - "integrity": "sha512-ooZWSDVAdh79Rrj4/nnfklL3NQVra0BcuhcuWoAwwi+znLDoUeH87AFfeX8s+YeYi6xlv5nveRyaA1v7CintfA==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "node_modules/jasmine-browser-runner/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/karma": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", - "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", - "dev": true, - "dependencies": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.7.2", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { - "karma": "bin/karma" + "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/karma-firefox-launcher": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-2.1.2.tgz", - "integrity": "sha512-VV9xDQU1QIboTrjtGVD4NCfzIH7n01ZXqy/qpBhnOeGVOkG5JYPEm8kuSd7psHE6WouZaQ9Ool92g8LFweSNMA==", - "dev": true, - "dependencies": { - "is-wsl": "^2.2.0", - "which": "^2.0.1" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/karma-jasmine": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.1.tgz", - "integrity": "sha512-h8XDAhTiZjJKzfkoO1laMH+zfNlra+dEQHUAjpn5JV1zCPtOIVWGQjLBrqhnzQa/hrU2XrZwSyBa6XjEBzfXzw==", + "node_modules/jasmine-browser-runner/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "jasmine-core": "^3.6.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 10" + "node": ">=16 || 14 >=14.17" }, - "peerDependencies": { - "karma": "*" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "node_modules/jasmine-core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.2.0.tgz", + "integrity": "sha512-tSAtdrvWybZkQmmaIoDgnvHG8ORUNw5kEVlO5CvrXj02Jjr9TZrmjFq7FUiOUzJiOP2wLGYT6PgrQgQF4R1xiw==", "dev": true }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - }, - "engines": { - "node": ">=8.0" + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" } }, - "node_modules/log4js/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "immediate": "~3.0.5" } }, - "node_modules/log4js/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, "node_modules/media-typer": { @@ -1039,16 +928,19 @@ "node": ">= 0.6" } }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "bin": { - "mime": "cli.js" - }, "engines": { - "node": ">=4.0.0" + "node": ">= 0.6" } }, "node_modules/mime-db": { @@ -1084,25 +976,13 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/ms": { @@ -1120,24 +1000,6 @@ "node": ">= 0.6" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -1147,26 +1009,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true }, "node_modules/parseurl": { "version": "1.3.3", @@ -1177,34 +1030,54 @@ "node": ">= 0.8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, "engines": { - "node": ">=8.6" + "node": ">=16 || 14 >=14.18" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, "engines": { - "node": ">=0.9" + "node": ">= 0.10" } }, "node_modules/qs": { @@ -1246,53 +1119,46 @@ "node": ">= 0.8" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -1300,213 +1166,231 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "node_modules/selenium-webdriver": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.23.0.tgz", + "integrity": "sha512-DdvtInpnMt95Td8VApvmAw7oSydBD9twIRXqoMyRoGMvL1dAnMFxdrwnW6L0d/pF/uoNTjbVUarwGZ9wIGNStA==", "dev": true, "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" + "@bazel/runfiles": "^5.8.1", + "jszip": "^3.10.1", + "tmp": "^0.2.3", + "ws": "^8.17.1" }, "engines": { - "node": ">= 0.4" + "node": ">= 14.21.0" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "node_modules/selenium-webdriver/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=10.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { - "node": ">=10.2.0" + "node": ">= 0.8.0" } }, - "node_modules/socket.io-adapter": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", - "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "dependencies": { - "debug": "~4.3.4", - "ws": "~8.11.0" + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" } }, - "node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ee-first": "1.1.1" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 0.8" } }, - "node_modules/socket.io-adapter/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { - "node": ">=10.0.0" + "node": ">= 0.8.0" } }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "dependencies": { - "ms": "2.1.2" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 0.4" } }, - "node_modules/socket.io-parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "dependencies": { - "ms": "2.1.2" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=8" } }, - "node_modules/socket.io/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, "engines": { - "node": ">=8.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "node_modules/streamroller/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "ms": "2.1.2" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=8" } }, - "node_modules/streamroller/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/string-width": { + "node_modules/string-width-cjs": { + "name": "string-width", "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", @@ -1532,28 +1416,38 @@ "node": ">=8" } }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "rimraf": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=8.17.0" + "node": ">=8" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "is-number": "^7.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=8.0" + "node": ">=8" + } + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" } }, "node_modules/toidentifier": { @@ -1578,44 +1472,6 @@ "node": ">= 0.6" } }, - "node_modules/ua-parser-js": { - "version": "0.7.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", - "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], - "engines": { - "node": "*" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1625,6 +1481,12 @@ "node": ">= 0.8" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1643,15 +1505,6 @@ "node": ">= 0.8" } }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -1667,7 +1520,8 @@ "node": ">= 8" } }, - "node_modules/wrap-ansi": { + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", @@ -1683,107 +1537,86 @@ "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } } }, "dependencies": { - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true - }, - "@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "@bazel/runfiles": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-5.8.1.tgz", + "integrity": "sha512-NDdfpdQ6rZlylgv++iMn5FkObC/QlBQvipinGLSOguTYpRywmieOyJ29XHvUilspwTFSILWpoE9CqMGkHXug1g==", "dev": true }, - "@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "requires": { - "@types/node": "*" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } } }, - "@types/node": { - "version": "20.11.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz", - "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==", + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "requires": { - "undici-types": "~5.26.4" - } + "optional": true }, "accepts": { "version": "1.3.8", @@ -1810,15 +1643,17 @@ "color-convert": "^2.0.1" } }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true }, "balanced-match": { "version": "1.0.2", @@ -1826,18 +1661,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, "body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -1879,15 +1702,6 @@ "concat-map": "0.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1907,31 +1721,14 @@ "set-function-length": "^1.2.1" } }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "color-convert": { @@ -1955,16 +1752,13 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "requires": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "safe-buffer": "5.2.1" } }, "content-type": { @@ -1973,34 +1767,29 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true }, - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "object-assign": "^4", - "vary": "^1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", - "dev": true - }, - "date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "dev": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2033,30 +1822,27 @@ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true }, - "di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, - "dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", - "dev": true, - "requires": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "requires": { + "jake": "^10.8.5" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2069,53 +1855,6 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, - "engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", - "dev": true, - "requires": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", - "dev": true - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true - }, "es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -2131,89 +1870,145 @@ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", "debug": "2.6.9", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } } }, - "flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true }, "function-bind": { "version": "1.1.2", @@ -2221,12 +2016,6 @@ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, "get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -2237,30 +2026,7 @@ "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" + "hasown": "^2.0.0" } }, "gopd": { @@ -2272,10 +2038,10 @@ "get-intrinsic": "^1.1.3" } }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "has-property-descriptors": { @@ -2329,17 +2095,6 @@ } } }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2349,15 +2104,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true }, "inherits": { "version": "2.0.4", @@ -2365,25 +2116,10 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true }, "is-fullwidth-code-point": { @@ -2392,34 +2128,10 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "isexe": { @@ -2428,118 +2140,123 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "jasmine-core": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.10.1.tgz", - "integrity": "sha512-ooZWSDVAdh79Rrj4/nnfklL3NQVra0BcuhcuWoAwwi+znLDoUeH87AFfeX8s+YeYi6xlv5nveRyaA1v7CintfA==", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "karma": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", - "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.7.2", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - } - }, - "karma-firefox-launcher": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-2.1.2.tgz", - "integrity": "sha512-VV9xDQU1QIboTrjtGVD4NCfzIH7n01ZXqy/qpBhnOeGVOkG5JYPEm8kuSd7psHE6WouZaQ9Ool92g8LFweSNMA==", + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "requires": { - "is-wsl": "^2.2.0", - "which": "^2.0.1" + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" } }, - "karma-jasmine": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.1.tgz", - "integrity": "sha512-h8XDAhTiZjJKzfkoO1laMH+zfNlra+dEQHUAjpn5JV1zCPtOIVWGQjLBrqhnzQa/hrU2XrZwSyBa6XjEBzfXzw==", + "jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "dev": true, "requires": { - "jasmine-core": "^3.6.0" + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "jasmine-browser-runner": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jasmine-browser-runner/-/jasmine-browser-runner-2.5.0.tgz", + "integrity": "sha512-CzdvpeZunUu6x1u8G6/vPnfcKVpDaBFfk3tIvm1hoA+EfceQ8FRvsy4o8hEcKYyMt556XFRnP5PjYsxFU8z7Xw==", "dev": true, "requires": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" + "ejs": "^3.1.6", + "express": "^4.19.2", + "glob": "^10.0.0", + "selenium-webdriver": "^4.12.0" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "ms": "2.1.2" + "balanced-match": "^1.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } } } }, + "jasmine-core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.2.0.tgz", + "integrity": "sha512-tSAtdrvWybZkQmmaIoDgnvHG8ORUNw5kEVlO5CvrXj02Jjr9TZrmjFq7FUiOUzJiOP2wLGYT6PgrQgQF4R1xiw==", + "dev": true + }, + "jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true }, "mime-db": { @@ -2566,21 +2283,12 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2593,41 +2301,23 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - }, "object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } + "package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true }, "parseurl": { "version": "1.3.3", @@ -2635,24 +2325,44 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", "dev": true }, - "qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, "qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -2680,47 +2390,123 @@ "unpipe": "1.0.0" } }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { - "picomatch": "^2.2.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", - "dev": true + "selenium-webdriver": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.23.0.tgz", + "integrity": "sha512-DdvtInpnMt95Td8VApvmAw7oSydBD9twIRXqoMyRoGMvL1dAnMFxdrwnW6L0d/pF/uoNTjbVUarwGZ9wIGNStA==", + "dev": true, + "requires": { + "@bazel/runfiles": "^5.8.1", + "jszip": "^3.10.1", + "tmp": "^0.2.3", + "ws": "^8.17.1" + }, + "dependencies": { + "ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "requires": {} + } + } }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "requires": { - "glob": "^7.1.3" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } }, "set-function-length": { "version": "1.2.2", @@ -2736,12 +2522,33 @@ "has-property-descriptors": "^1.0.2" } }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -2754,134 +2561,42 @@ "object-inspect": "^1.13.1" } }, - "socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "socket.io-adapter": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", - "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", - "dev": true, - "requires": { - "debug": "~4.3.4", - "ws": "~8.11.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true }, - "socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" + "safe-buffer": "~5.1.0" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true } } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "string-width": { - "version": "4.2.3", + "string-width-cjs": { + "version": "npm:string-width@4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, @@ -2900,24 +2615,30 @@ "ansi-regex": "^5.0.1" } }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "rimraf": "^3.0.0" + "ansi-regex": "^5.0.1" } }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "is-number": "^7.0.0" + "has-flag": "^4.0.0" } }, + "tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -2934,30 +2655,18 @@ "mime-types": "~2.1.24" } }, - "ua-parser-js": { - "version": "0.7.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", - "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", - "dev": true - }, - "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2970,12 +2679,6 @@ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true }, - "void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "dev": true - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2985,8 +2688,8 @@ "isexe": "^2.0.0" } }, - "wrap-ansi": { - "version": "7.0.0", + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, @@ -2995,46 +2698,6 @@ "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "requires": {} - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true } } } diff --git a/package.json b/package.json index 451f5e20a11..3a25f9bb3fd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sphinx", "scripts": { - "test": "./node_modules/.bin/karma start --browsers Firefox --single-run" + "test": "npx jasmine-browser-runner runSpecs --config=tests/js/jasmine-browser.mjs" }, "repository": { "type": "git", @@ -11,9 +11,7 @@ "url": "https://github.com/sphinx-doc/sphinx/issues" }, "devDependencies": { - "jasmine-core": "^3.4.0", - "karma": "^6.3.16", - "karma-firefox-launcher": "^2.0.0", - "karma-jasmine": "^4.0.0" + "jasmine-browser-runner": "^2.5.0", + "jasmine-core": "^5.2.0" } } diff --git a/tests/js/jasmine-browser.mjs b/tests/js/jasmine-browser.mjs new file mode 100644 index 00000000000..fd45a1e3b59 --- /dev/null +++ b/tests/js/jasmine-browser.mjs @@ -0,0 +1,29 @@ +export default { + srcDir: ".", + srcFiles: [ + 'sphinx/themes/basic/static/doctools.js', + 'sphinx/themes/basic/static/searchtools.js', + 'sphinx/themes/basic/static/sphinx_highlight.js', + 'tests/js/fixtures/**/*.js', + 'tests/js/documentation_options.js', + 'tests/js/language_data.js', + ], + specDir: "tests/js", + specFiles: [ + 'searchtools.js', + 'sphinx_highlight.js' + ], + helpers: [], + env: { + stopSpecOnExpectationFailure: false, + stopOnSpecFailure: false, + random: true + }, + + listenAddress: "127.0.0.1", + hostname: "127.0.0.1", + + browser: { + name: "firefox" + } +}; diff --git a/tests/js/searchtools.js b/tests/js/searchtools.js index c82c6f1f968..407fcd2bfe9 100644 --- a/tests/js/searchtools.js +++ b/tests/js/searchtools.js @@ -2,7 +2,7 @@ describe('Basic html theme search', function() { function loadFixture(name) { req = new XMLHttpRequest(); - req.open("GET", `base/tests/js/fixtures/${name}`, false); + req.open("GET", `__src__/tests/js/fixtures/${name}`, false); req.send(null); return req.responseText; } From d7a22c2d0a93a65ec721963edb743dde3783a430 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 10 Aug 2024 21:23:25 +0100 Subject: [PATCH 05/24] Add lower-bounds to the ``sphinxcontrib-*`` dependencies (#12756) --- .github/workflows/main.yml | 33 +++++++++++++++++++++++++++++++++ CHANGES.rst | 3 +++ pyproject.toml | 10 +++++----- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 293d3e4de6e..b4804d01ad0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,6 +23,7 @@ env: FORCE_COLOR: "1" PYTHONDEVMODE: "1" # -X dev PYTHONWARNDEFAULTENCODING: "1" # -X warn_default_encoding + UV_SYSTEM_PYTHON: "1" # make uv do global installs jobs: ubuntu: @@ -124,6 +125,38 @@ jobs: DO_EPUBCHECK: "1" EPUBCHECK_PATH: "/tmp/epubcheck/epubcheck-5.1.0/epubcheck.jar" + oldest-supported: + runs-on: ubuntu-latest + name: Oldest supported + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3" + - name: Check Python version + run: python --version --version + - name: Install graphviz + run: sudo apt-get install graphviz + - name: Install uv + run: > + curl + --location + --fail + --proto '=https' --tlsv1.2 + --silent --show-error + https://astral.sh/uv/install.sh + | sh + - name: Install dependencies + run: | + uv pip install .[test] --resolution lowest-direct + uv pip install alabaster==1.0.0 + - name: Test with pytest + run: python -m pytest -vv --durations 25 + env: + PYTHONWARNINGS: "error" # treat all warnings as errors + latex: runs-on: ubuntu-latest name: LaTeX diff --git a/CHANGES.rst b/CHANGES.rst index c629a6d9a55..99fc230cdad 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,9 @@ Release 8.1.0 (in development) Dependencies ------------ +* #12756: Add lower-bounds to the ``sphinxcontrib-*`` dependencies. + Patch by Adam Turner. + Incompatible changes -------------------- diff --git a/pyproject.toml b/pyproject.toml index 752769377d2..ff26246c2a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,12 +55,12 @@ classifiers = [ "Topic :: Utilities", ] dependencies = [ - "sphinxcontrib-applehelp", - "sphinxcontrib-devhelp", - "sphinxcontrib-jsmath", - "sphinxcontrib-htmlhelp>=2.0.0", + "sphinxcontrib-applehelp>=1.0.7", + "sphinxcontrib-devhelp>=1.0.6", + "sphinxcontrib-htmlhelp>=2.0.6", + "sphinxcontrib-jsmath>=1.0.1", + "sphinxcontrib-qthelp>=1.0.6", "sphinxcontrib-serializinghtml>=1.1.9", - "sphinxcontrib-qthelp", "Jinja2>=3.1", "Pygments>=2.17", "docutils>=0.20,<0.22", From 18fbced7e06d81b76ac2fc8f5ac46da3fa9abc85 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 11 Aug 2024 00:19:50 +0100 Subject: [PATCH 06/24] Reduce the formatter's target line length to 88 (#12757) --- .ruff.toml | 5 +- doc/conf.py | 13 ++++- doc/development/tutorials/examples/recipe.py | 19 ++++++- doc/development/tutorials/examples/todo.py | 8 ++- sphinx/__init__.py | 5 +- sphinx/builders/__init__.py | 15 +++++- sphinx/builders/html/__init__.py | 6 ++- sphinx/builders/latex/__init__.py | 6 ++- sphinx/deprecation.py | 10 +++- sphinx/environment/__init__.py | 7 ++- sphinx/errors.py | 5 +- sphinx/events.py | 10 +++- sphinx/ext/apidoc.py | 53 ++++++++++++++----- sphinx/ext/autosummary/generate.py | 30 ++++++++--- sphinx/highlighting.py | 11 +++- sphinx/jinja2glue.py | 8 ++- sphinx/locale/__init__.py | 8 ++- sphinx/parsers.py | 4 +- sphinx/project.py | 8 ++- sphinx/roles.py | 14 +++-- sphinx/theming.py | 24 ++++++--- sphinx/versioning.py | 4 +- tests/test_environment/test_environment.py | 7 ++- tests/test_util/test_util_docstrings.py | 6 ++- .../test_util_docutils_sphinx_directive.py | 7 ++- tests/test_util/test_util_inspect.py | 6 ++- utils/babel_runner.py | 8 ++- utils/bump_version.py | 8 ++- 28 files changed, 250 insertions(+), 65 deletions(-) diff --git a/.ruff.toml b/.ruff.toml index 2b0e3434aa9..4938e32211f 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -1,5 +1,5 @@ target-version = "py310" # Pin Ruff to Python 3.10 -line-length = 95 +line-length = 88 output-format = "full" extend-exclude = [ @@ -427,6 +427,9 @@ select = [ "ANN", # utilities don't need annotations ] +[lint.pycodestyle] +max-line-length = 95 + [lint.flake8-quotes] inline-quotes = "single" diff --git a/doc/conf.py b/doc/conf.py index ffb9d19bd07..fc86fcd6d98 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -77,7 +77,14 @@ epub_description = 'Sphinx documentation generator system manual' latex_documents = [ - ('index', 'sphinx.tex', 'Sphinx Documentation', 'the Sphinx developers', 'manual', 1) + ( + 'index', + 'sphinx.tex', + 'Sphinx Documentation', + 'the Sphinx developers', + 'manual', + 1, + ) ] latex_logo = '_static/sphinx.png' latex_elements = { @@ -324,7 +331,9 @@ def setup(app: Sphinx) -> None: app.connect('autodoc-process-docstring', cut_lines(4, what=['module'])) app.connect('include-read', linkify_issues_in_changelog) app.connect('build-finished', build_redirects) - fdesc = GroupedField('parameter', label='Parameters', names=['param'], can_collapse=True) + fdesc = GroupedField( + 'parameter', label='Parameters', names=['param'], can_collapse=True + ) app.add_object_type( 'event', 'event', diff --git a/doc/development/tutorials/examples/recipe.py b/doc/development/tutorials/examples/recipe.py index baf85fe3e2c..9848629216a 100644 --- a/doc/development/tutorials/examples/recipe.py +++ b/doc/development/tutorials/examples/recipe.py @@ -62,7 +62,15 @@ def generate(self, docnames=None): for ingredient, recipe_names in ingredient_recipes.items(): for recipe_name in recipe_names: dispname, typ, docname, anchor = recipes[recipe_name] - content[ingredient].append((dispname, 0, docname, anchor, docname, '', typ)) + content[ingredient].append(( + dispname, + 0, + docname, + anchor, + docname, + '', + typ, + )) # convert the dict to the sorted list of tuples expected content = sorted(content.items()) @@ -153,7 +161,14 @@ def add_recipe(self, signature, ingredients): self.data['recipe_ingredients'][name] = ingredients # name, dispname, type, docname, anchor, priority - self.data['recipes'].append((name, signature, 'Recipe', self.env.docname, anchor, 0)) + self.data['recipes'].append(( + name, + signature, + 'Recipe', + self.env.docname, + anchor, + 0, + )) def setup(app: Sphinx) -> ExtensionMetadata: diff --git a/doc/development/tutorials/examples/todo.py b/doc/development/tutorials/examples/todo.py index 4e9dc66855e..25aedfb0543 100644 --- a/doc/development/tutorials/examples/todo.py +++ b/doc/development/tutorials/examples/todo.py @@ -57,7 +57,9 @@ def purge_todos(app, env, docname): if not hasattr(env, 'todo_all_todos'): return - env.todo_all_todos = [todo for todo in env.todo_all_todos if todo['docname'] != docname] + env.todo_all_todos = [ + todo for todo in env.todo_all_todos if todo['docname'] != docname + ] def merge_todos(app, env, docnames, other): @@ -98,7 +100,9 @@ def process_todo_nodes(app, doctree, fromdocname): newnode = nodes.reference('', '') innernode = nodes.emphasis(_('here'), _('here')) newnode['refdocname'] = todo_info['docname'] - newnode['refuri'] = app.builder.get_relative_uri(fromdocname, todo_info['docname']) + newnode['refuri'] = app.builder.get_relative_uri( + fromdocname, todo_info['docname'] + ) newnode['refuri'] += '#' + todo_info['target']['refid'] newnode.append(innernode) para += newnode diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 85397059f59..bf62f813e07 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -16,7 +16,10 @@ warnings.filterwarnings('default', category=RemovedInNextVersionWarning) warnings.filterwarnings( - 'ignore', 'The frontend.Option class .*', DeprecationWarning, module='docutils.frontend' + 'ignore', + 'The frontend.Option class .*', + DeprecationWarning, + module='docutils.frontend', ) #: Version info for better programmatic use. diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 151df6aeb18..8a51cbb6717 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -16,14 +16,25 @@ from sphinx.environment.adapters.asset import ImageAdapter from sphinx.errors import SphinxError from sphinx.locale import __ -from sphinx.util import UnicodeDecodeErrorHandler, get_filetype, import_object, logging, rst +from sphinx.util import ( + UnicodeDecodeErrorHandler, + get_filetype, + import_object, + logging, + rst, +) from sphinx.util.build_phase import BuildPhase from sphinx.util.console import bold from sphinx.util.display import progress_message, status_iterator from sphinx.util.docutils import sphinx_domains from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain from sphinx.util.osutil import SEP, canon_path, ensuredir, relative_uri, relpath -from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available +from sphinx.util.parallel import ( + ParallelTasks, + SerialTasks, + make_chunks, + parallel_available, +) # side effect: registers roles and directives from sphinx import directives # NoQA: F401 isort:skip diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index 8f351b76a12..78b9accccd6 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -26,7 +26,11 @@ from sphinx import __display_version__, package_dir from sphinx import version_info as sphinx_version from sphinx.builders import Builder -from sphinx.builders.html._assets import _CascadingStyleSheet, _file_checksum, _JavaScript +from sphinx.builders.html._assets import ( + _CascadingStyleSheet, + _file_checksum, + _JavaScript, +) from sphinx.config import ENUM, Config from sphinx.deprecation import _deprecation_warning from sphinx.domains import Domain, Index, IndexEntry diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index 508c676312f..f19d66edbc9 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -12,7 +12,11 @@ import sphinx.builders.latex.nodes # NoQA: F401,E501 # Workaround: import this before writer to avoid ImportError from sphinx import addnodes, highlighting, package_dir from sphinx.builders import Builder -from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTINGS, SHORTHANDOFF +from sphinx.builders.latex.constants import ( + ADDITIONAL_SETTINGS, + DEFAULT_SETTINGS, + SHORTHANDOFF, +) from sphinx.builders.latex.theming import Theme, ThemeFactory from sphinx.builders.latex.util import ExtBabel from sphinx.config import ENUM, Config diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index 8605e418826..1baec85bf7a 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -40,7 +40,11 @@ def _deprecation_warning( # deprecated name -> (object to return, canonical path or empty string, removal version) _DEPRECATED_OBJECTS = { - 'deprecated_name': (object_to_return, 'fully_qualified_replacement_name', (9, 0)), + 'deprecated_name': ( + object_to_return, + 'fully_qualified_replacement_name', + (9, 0), + ), } @@ -65,7 +69,9 @@ def __getattr__(name: str) -> Any: qualname = f'{module}.{attribute}' if canonical_name: - message = f'The alias {qualname!r} is deprecated, use {canonical_name!r} instead.' + message = ( + f'The alias {qualname!r} is deprecated, use {canonical_name!r} instead.' + ) else: message = f'{qualname!r} is deprecated.' diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 20bfd86bc75..7aef2ea0667 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -12,7 +12,12 @@ from sphinx import addnodes from sphinx.environment.adapters import toctree as toctree_adapters -from sphinx.errors import BuildEnvironmentError, DocumentError, ExtensionError, SphinxError +from sphinx.errors import ( + BuildEnvironmentError, + DocumentError, + ExtensionError, + SphinxError, +) from sphinx.locale import __ from sphinx.transforms import SphinxTransformer from sphinx.util import DownloadFiles, FilenameUniqDict, logging diff --git a/sphinx/errors.py b/sphinx/errors.py index 44df3e8da95..c0339b4e998 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -45,7 +45,10 @@ class ExtensionError(SphinxError): """Extension error.""" def __init__( - self, message: str, orig_exc: Exception | None = None, modname: str | None = None + self, + message: str, + orig_exc: Exception | None = None, + modname: str | None = None, ) -> None: super().__init__(message) self.message = message diff --git a/sphinx/events.py b/sphinx/events.py index 4dc5131e7ee..df2fdf7048d 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -84,7 +84,10 @@ def disconnect(self, listener_id: int) -> None: listeners.remove(listener) def emit( - self, name: str, *args: Any, allowed_exceptions: tuple[type[Exception], ...] = () + self, + name: str, + *args: Any, + allowed_exceptions: tuple[type[Exception], ...] = (), ) -> list: """Emit a Sphinx event.""" # not every object likes to be repr()'d (think @@ -120,7 +123,10 @@ def emit( return results def emit_firstresult( - self, name: str, *args: Any, allowed_exceptions: tuple[type[Exception], ...] = () + self, + name: str, + *args: Any, + allowed_exceptions: tuple[type[Exception], ...] = (), ) -> Any: """Emit a Sphinx event and returns first result. diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 53bc2ea370e..077f58624d2 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -96,7 +96,10 @@ def write_file(name: str, text: str, opts: CliOptions) -> Path: def create_module_file( - package: str | None, basename: str, opts: CliOptions, user_template_dir: str | None = None + package: str | None, + basename: str, + opts: CliOptions, + user_template_dir: str | None = None, ) -> Path: """Build the text of the file and write the file.""" options = copy(OPTIONS) @@ -148,7 +151,9 @@ def create_package_file( if not is_skipped_module(Path(root, sub), opts, excludes) and not is_initpy(sub) ] submodules = sorted(set(submodules)) - submodules = [module_join(master_package, subroot, modname) for modname in submodules] + submodules = [ + module_join(master_package, subroot, modname) for modname in submodules + ] options = copy(OPTIONS) if opts.includeprivate and 'private-members' not in options: options.append('private-members') @@ -316,7 +321,9 @@ def recurse_tree( if is_pkg or is_namespace: # we are in a package with something to document if subs or len(files) > 1 or not is_skipped_package(root, opts): - subpackage = root[len(rootpath) :].lstrip(path.sep).replace(path.sep, '.') + subpackage = ( + root[len(rootpath) :].lstrip(path.sep).replace(path.sep, '.') + ) # if this is not a namespace or # a namespace and there is something there to document if not is_namespace or has_child_module(root, excludes, opts): @@ -342,7 +349,9 @@ def recurse_tree( if not is_skipped_module(Path(rootpath, py_file), opts, excludes): module = py_file.split('.')[0] written_files.append( - create_module_file(root_package, module, opts, user_template_dir) + create_module_file( + root_package, module, opts, user_template_dir + ) ) toplevels.append(module) @@ -361,7 +370,7 @@ def is_excluded(root: str | Path, excludes: Sequence[re.Pattern[str]]) -> bool: def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - usage='%(prog)s [OPTIONS] -o ' '[EXCLUDE_PATTERN, ...]', + usage='%(prog)s [OPTIONS] -o [EXCLUDE_PATTERN, ...]', epilog=__('For more information, visit .'), description=__(""" Look recursively in for Python modules and packages and create @@ -384,7 +393,9 @@ def get_parser() -> argparse.ArgumentParser: parser.add_argument( 'exclude_pattern', nargs='*', - help=__('fnmatch-style file and/or directory patterns ' 'to exclude from generation'), + help=__( + 'fnmatch-style file and/or directory patterns ' 'to exclude from generation' + ), ) parser.add_argument( @@ -411,7 +422,11 @@ def get_parser() -> argparse.ArgumentParser: help=__('maximum depth of submodules to show in the TOC ' '(default: 4)'), ) parser.add_argument( - '-f', '--force', action='store_true', dest='force', help=__('overwrite existing files') + '-f', + '--force', + action='store_true', + dest='force', + help=__('overwrite existing files'), ) parser.add_argument( '-l', @@ -420,7 +435,8 @@ def get_parser() -> argparse.ArgumentParser: dest='followlinks', default=False, help=__( - 'follow symbolic links. Powerful when combined ' 'with collective.recipe.omelette.' + 'follow symbolic links. Powerful when combined ' + 'with collective.recipe.omelette.' ), ) parser.add_argument( @@ -481,7 +497,8 @@ def get_parser() -> argparse.ArgumentParser: action='store_true', dest='implicit_namespaces', help=__( - 'interpret module paths according to PEP-0420 ' 'implicit namespaces specification' + 'interpret module paths according to PEP-0420 ' + 'implicit namespaces specification' ), ) parser.add_argument( @@ -497,7 +514,9 @@ def get_parser() -> argparse.ArgumentParser: '--remove-old', action='store_true', dest='remove_old', - help=__('Remove existing files in the output directory that were not generated'), + help=__( + 'Remove existing files in the output directory that were not generated' + ), ) exclusive_group.add_argument( '-F', @@ -539,7 +558,9 @@ def get_parser() -> argparse.ArgumentParser: '--doc-release', action='store', dest='release', - help=__('project release, used when --full is given, ' 'defaults to --doc-version'), + help=__( + 'project release, used when --full is given, ' 'defaults to --doc-version' + ), ) group = parser.add_argument_group(__('extension options')) @@ -649,7 +670,11 @@ def main(argv: Sequence[str] = (), /) -> int: 'suffix': '.' + args.suffix, 'master': 'index', 'epub': True, - 'extensions': ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.todo'], + 'extensions': [ + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', + 'sphinx.ext.todo', + ], 'makefile': True, 'batchfile': True, 'make_mode': True, @@ -670,7 +695,9 @@ def main(argv: Sequence[str] = (), /) -> int: d['extensions'].extend(ext.split(',')) if not args.dryrun: - qs.generate(d, silent=True, overwrite=args.force, templatedir=args.templatedir) + qs.generate( + d, silent=True, overwrite=args.force, templatedir=args.templatedir + ) elif args.tocfile: written_files.append( create_modules_toc_file(modules, args, args.tocfile, args.templatedir) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 356043e1e68..eab9d00b17a 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -131,7 +131,9 @@ def __init__(self, app: Sphinx) -> None: msg = 'Expected a Sphinx application object!' raise ValueError(msg) - system_templates_path = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')] + system_templates_path = [ + os.path.join(package_dir, 'ext', 'autosummary', 'templates') + ] loader = SphinxTemplateLoader( app.srcdir, app.config.templates_path, system_templates_path ) @@ -297,7 +299,9 @@ def generate_autosummary_content( ns['members'] = scanner.scan(imported_members) respect_module_all = not app.config.autosummary_ignore_module_all - imported_members = imported_members or ('__all__' in dir(obj) and respect_module_all) + imported_members = imported_members or ( + '__all__' in dir(obj) and respect_module_all + ) ns['functions'], ns['all_functions'] = _get_members( doc, app, obj, {'function'}, imported=imported_members @@ -378,7 +382,9 @@ def generate_autosummary_content( def _skip_member(app: Sphinx, obj: Any, name: str, objtype: str) -> bool: try: - return app.emit_firstresult('autodoc-skip-member', objtype, name, obj, False, {}) + return app.emit_firstresult( + 'autodoc-skip-member', objtype, name, obj, False, {} + ) except Exception as exc: logger.warning( __( @@ -465,7 +471,11 @@ def _get_module_attrs(name: str, members: Any) -> tuple[list[str], list[str]]: def _get_modules( - obj: Any, *, skip: Sequence[str], name: str, public_members: Sequence[str] | None = None + obj: Any, + *, + skip: Sequence[str], + name: str, + public_members: Sequence[str] | None = None, ) -> tuple[list[str], list[str]]: items: list[str] = [] public: list[str] = [] @@ -511,7 +521,9 @@ def generate_autosummary_docs( showed_sources = sorted(sources) if len(showed_sources) > 20: showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:] - logger.info(__('[autosummary] generating autosummary for: %s'), ', '.join(showed_sources)) + logger.info( + __('[autosummary] generating autosummary for: %s'), ', '.join(showed_sources) + ) if output_dir: logger.info(__('[autosummary] writing to %s'), output_dir) @@ -736,7 +748,9 @@ def find_autosummary_in_lines( if m: current_module = m.group(1).strip() # recurse into the automodule docstring - documented.extend(find_autosummary_in_docstring(current_module, filename=filename)) + documented.extend( + find_autosummary_in_docstring(current_module, filename=filename) + ) continue m = module_re.match(line) @@ -823,7 +837,9 @@ def get_parser() -> argparse.ArgumentParser: action='store_true', dest='remove_old', default=False, - help=__('Remove existing files in the output directory that were not generated'), + help=__( + 'Remove existing files in the output directory that were not generated' + ), ) return parser diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index 86bdd234430..c7ae156689d 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -48,7 +48,11 @@ } -escape_hl_chars = {ord('\\'): '\\PYGZbs{}', ord('{'): '\\PYGZob{}', ord('}'): '\\PYGZcb{}'} +escape_hl_chars = { + ord('\\'): '\\PYGZbs{}', + ord('{'): '\\PYGZob{}', + ord('}'): '\\PYGZcb{}', +} # used if Pygments is available # MEMO: no use of \protected here to avoid having to do hyperref extras, @@ -96,7 +100,10 @@ class PygmentsBridge: latex_formatter = LatexFormatter[str] def __init__( - self, dest: str = 'html', stylename: str = 'sphinx', latex_engine: str | None = None + self, + dest: str = 'html', + stylename: str = 'sphinx', + latex_engine: str | None = None, ) -> None: self.dest = dest self.latex_engine = latex_engine diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index 74321383455..0df58b52d4f 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -116,7 +116,9 @@ class SphinxFileSystemLoader(FileSystemLoader): template names. """ - def get_source(self, environment: Environment, template: str) -> tuple[str, str, Callable]: + def get_source( + self, environment: Environment, template: str + ) -> tuple[str, str, Callable]: for searchpath in self.searchpath: filename = path.join(searchpath, template) f = open_if_exists(filename) @@ -220,7 +222,9 @@ def _newest_template_mtime_name(self) -> tuple[float, str]: # Loader interface - def get_source(self, environment: Environment, template: str) -> tuple[str, str, Callable]: + def get_source( + self, environment: Environment, template: str + ) -> tuple[str, str, Callable]: loaders = self.loaders # exclamation mark starts search from theme if template.startswith('!'): diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index c0b4ee9adff..1d66c8e1e45 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -166,11 +166,15 @@ def init_console( return init([locale_dir], language, catalog, 'console') -def get_translator(catalog: str = 'sphinx', namespace: str = 'general') -> NullTranslations: +def get_translator( + catalog: str = 'sphinx', namespace: str = 'general' +) -> NullTranslations: return translators.get((namespace, catalog), NullTranslations()) -def is_translator_registered(catalog: str = 'sphinx', namespace: str = 'general') -> bool: +def is_translator_registered( + catalog: str = 'sphinx', namespace: str = 'general' +) -> bool: return (namespace, catalog) in translators diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 955d59b3b79..cc10ce184b1 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -72,7 +72,9 @@ def parse(self, inputstring: str | StringList, document: nodes.document) -> None # preprocess inputstring if isinstance(inputstring, str): lines = docutils.statemachine.string2lines( - inputstring, tab_width=document.settings.tab_width, convert_whitespace=True + inputstring, + tab_width=document.settings.tab_width, + convert_whitespace=True, ) inputlines = StringList(lines, document.current_source) diff --git a/sphinx/project.py b/sphinx/project.py index f1d77a351a0..01642999306 100644 --- a/sphinx/project.py +++ b/sphinx/project.py @@ -23,7 +23,9 @@ class Project: """A project is the source code set of the Sphinx document(s).""" - def __init__(self, srcdir: str | os.PathLike[str], source_suffix: Iterable[str]) -> None: + def __init__( + self, srcdir: str | os.PathLike[str], source_suffix: Iterable[str] + ) -> None: #: Source directory. self.srcdir = _StrPath(srcdir) @@ -82,7 +84,9 @@ def discover( self._docname_to_path[docname] = path else: logger.warning( - __('Ignored unreadable document %r.'), filename, location=docname + __('Ignored unreadable document %r.'), + filename, + location=docname, ) return self.docnames diff --git a/sphinx/roles.py b/sphinx/roles.py index fbc322dcf5b..182e2c0da24 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -167,7 +167,11 @@ def process_link( return title, ws_re.sub(' ', target) def result_nodes( - self, document: nodes.document, env: BuildEnvironment, node: Element, is_ref: bool + self, + document: nodes.document, + env: BuildEnvironment, + node: Element, + is_ref: bool, ) -> tuple[list[Node], list[system_message]]: """Called before returning the finished nodes. *node* is the reference node if one was created (*is_ref* is then true), else the content node. @@ -211,7 +215,9 @@ def run(self) -> tuple[list[Node], list[system_message]]: try: refuri = self.build_uri() - reference = nodes.reference('', '', internal=False, refuri=refuri, classes=['pep']) + reference = nodes.reference( + '', '', internal=False, refuri=refuri, classes=['pep'] + ) if self.has_explicit_title: reference += nodes.strong(self.title, self.title) else: @@ -246,7 +252,9 @@ def run(self) -> tuple[list[Node], list[system_message]]: try: refuri = self.build_uri() - reference = nodes.reference('', '', internal=False, refuri=refuri, classes=['rfc']) + reference = nodes.reference( + '', '', internal=False, refuri=refuri, classes=['rfc'] + ) if self.has_explicit_title: reference += nodes.strong(self.title, self.title) else: diff --git a/sphinx/theming.py b/sphinx/theming.py index b132c8bcd24..6d9986ba3c2 100644 --- a/sphinx/theming.py +++ b/sphinx/theming.py @@ -293,7 +293,9 @@ def _load_theme_with_ancestors( return themes, theme_dirs, tmp_dirs -def _load_theme(name: str, theme_path: str, /) -> tuple[str, str, str | None, _ConfigFile]: +def _load_theme( + name: str, theme_path: str, / +) -> tuple[str, str, str | None, _ConfigFile]: if path.isdir(theme_path): # already a directory, do nothing tmp_dir = None @@ -371,7 +373,9 @@ def _convert_theme_toml(cfg: _ThemeToml, /) -> _ConfigFile: pygments_table = theme.get('pygments_style', {}) if isinstance(pygments_table, str): hint = f'pygments_style = {{ default = "{pygments_table}" }}' - msg = __('The "theme.pygments_style" setting must be a table. Hint: "%s"') % hint + msg = ( + __('The "theme.pygments_style" setting must be a table. Hint: "%s"') % hint + ) raise ThemeError(msg) pygments_style_default: str | None = pygments_table.get('default') pygments_style_dark: str | None = pygments_table.get('dark') @@ -401,15 +405,23 @@ def _validate_theme_conf(cfg: configparser.RawConfigParser, name: str) -> str: def _convert_theme_conf(cfg: configparser.RawConfigParser, /) -> _ConfigFile: if stylesheet := cfg.get('theme', 'stylesheet', fallback=''): - stylesheets: tuple[str, ...] | None = tuple(map(str.strip, stylesheet.split(','))) + stylesheets: tuple[str, ...] | None = tuple( + map(str.strip, stylesheet.split(',')) + ) else: stylesheets = None if sidebar := cfg.get('theme', 'sidebars', fallback=''): - sidebar_templates: tuple[str, ...] | None = tuple(map(str.strip, sidebar.split(','))) + sidebar_templates: tuple[str, ...] | None = tuple( + map(str.strip, sidebar.split(',')) + ) else: sidebar_templates = None - pygments_style_default: str | None = cfg.get('theme', 'pygments_style', fallback=None) - pygments_style_dark: str | None = cfg.get('theme', 'pygments_dark_style', fallback=None) + pygments_style_default: str | None = cfg.get( + 'theme', 'pygments_style', fallback=None + ) + pygments_style_dark: str | None = cfg.get( + 'theme', 'pygments_dark_style', fallback=None + ) options = dict(cfg.items('options')) if cfg.has_section('options') else {} return _ConfigFile( stylesheets=stylesheets, diff --git a/sphinx/versioning.py b/sphinx/versioning.py index 8756fabe4ba..506d7b5753d 100644 --- a/sphinx/versioning.py +++ b/sphinx/versioning.py @@ -45,7 +45,9 @@ def add_uids(doctree: Node, condition: Callable[[Node], bool]) -> Iterator[Node] yield node -def merge_doctrees(old: Node, new: Node, condition: Callable[[Node], bool]) -> Iterator[Node]: +def merge_doctrees( + old: Node, new: Node, condition: Callable[[Node], bool] +) -> Iterator[Node]: """Merge the `old` doctree with the `new` one while looking at nodes matching the `condition`. diff --git a/tests/test_environment/test_environment.py b/tests/test_environment/test_environment.py index 82de5975877..7f24f0570e0 100644 --- a/tests/test_environment/test_environment.py +++ b/tests/test_environment/test_environment.py @@ -7,7 +7,12 @@ from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.latex import LaTeXBuilder -from sphinx.environment import CONFIG_CHANGED, CONFIG_EXTENSIONS_CHANGED, CONFIG_NEW, CONFIG_OK +from sphinx.environment import ( + CONFIG_CHANGED, + CONFIG_EXTENSIONS_CHANGED, + CONFIG_NEW, + CONFIG_OK, +) @pytest.mark.sphinx('dummy', testroot='basic') diff --git a/tests/test_util/test_util_docstrings.py b/tests/test_util/test_util_docstrings.py index 813e84e975e..ed194fedb22 100644 --- a/tests/test_util/test_util_docstrings.py +++ b/tests/test_util/test_util_docstrings.py @@ -1,6 +1,10 @@ """Test sphinx.util.docstrings.""" -from sphinx.util.docstrings import prepare_commentdoc, prepare_docstring, separate_metadata +from sphinx.util.docstrings import ( + prepare_commentdoc, + prepare_docstring, + separate_metadata, +) def test_separate_metadata(): diff --git a/tests/test_util/test_util_docutils_sphinx_directive.py b/tests/test_util/test_util_docutils_sphinx_directive.py index 8f5ab3f8e38..f47cfc27e35 100644 --- a/tests/test_util/test_util_docutils_sphinx_directive.py +++ b/tests/test_util/test_util_docutils_sphinx_directive.py @@ -4,7 +4,12 @@ from docutils import nodes from docutils.parsers.rst.languages import en as english # type: ignore[attr-defined] -from docutils.parsers.rst.states import Inliner, RSTState, RSTStateMachine, state_classes +from docutils.parsers.rst.states import ( + Inliner, + RSTState, + RSTStateMachine, + state_classes, +) from docutils.statemachine import StringList from sphinx.util.docutils import SphinxDirective, new_document diff --git a/tests/test_util/test_util_inspect.py b/tests/test_util/test_util_inspect.py index 9ddab510b99..3d14becfe04 100644 --- a/tests/test_util/test_util_inspect.py +++ b/tests/test_util/test_util_inspect.py @@ -14,7 +14,11 @@ import pytest from sphinx.util import inspect -from sphinx.util.inspect import TypeAliasForwardRef, TypeAliasNamespace, stringify_signature +from sphinx.util.inspect import ( + TypeAliasForwardRef, + TypeAliasNamespace, + stringify_signature, +) from sphinx.util.typing import stringify_annotation diff --git a/utils/babel_runner.py b/utils/babel_runner.py index 3bba578d8bf..63a68d9f866 100644 --- a/utils/babel_runner.py +++ b/utils/babel_runner.py @@ -183,7 +183,9 @@ def run_compile() -> None: catalogue = read_po(infile, locale=locale.name) if catalogue.fuzzy: - log.info('catalogue %s is marked as fuzzy, skipping', po_file.relative_to(ROOT)) + log.info( + 'catalogue %s is marked as fuzzy, skipping', po_file.relative_to(ROOT) + ) continue locale_errors = 0 @@ -250,7 +252,9 @@ def run_compile() -> None: _write_pr_body_line('## Babel catalogue errors') _write_pr_body_line('') for locale_name, err_count in total_errors.items(): - log.error('error: %d errors encountered in %r locale.', err_count, locale_name) + log.error( + 'error: %d errors encountered in %r locale.', err_count, locale_name + ) s = 's' if err_count != 1 else '' _write_pr_body_line(f'* {locale_name}: {err_count} error{s}') diff --git a/utils/bump_version.py b/utils/bump_version.py index 826fc4a782d..81824fc0a1c 100755 --- a/utils/bump_version.py +++ b/utils/bump_version.py @@ -80,7 +80,9 @@ def parse_version(version: str) -> VersionInfo: raise RuntimeError(msg) -def bump_version(path: Path, version_info: VersionInfo, in_develop: bool = True) -> None: +def bump_version( + path: Path, version_info: VersionInfo, in_develop: bool = True +) -> None: if in_develop or version_info.is_final: version = version_info.version else: @@ -150,7 +152,9 @@ def add_release(self, version_info: VersionInfo) -> None: @staticmethod def filter_empty_sections(body: str) -> str: - return re.sub('^\n.+\n-{3,}\n+(?=\n.+\n[-=]{3,}\n)', '', body, flags=re.MULTILINE) + return re.sub( + '^\n.+\n-{3,}\n+(?=\n.+\n[-=]{3,}\n)', '', body, flags=re.MULTILINE + ) class Skip(Exception): From 620e434f651b298cd5e852f579dce7b631a5db7b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 11 Aug 2024 00:39:35 +0100 Subject: [PATCH 07/24] Improve string concatenation (#12758) Use implicit concatenation over ``+``, and combine some implicit concatenations to a single string literal. --- sphinx/domains/c/_parser.py | 16 +++++++---- sphinx/domains/cpp/_parser.py | 15 +++++----- sphinx/ext/apidoc.py | 14 ++++------ sphinx/ext/autosummary/generate.py | 6 ++-- sphinx/ext/coverage.py | 2 +- sphinx/transforms/i18n.py | 10 +++---- tests/test_builders/test_build_html_code.py | 2 +- tests/test_builders/test_build_latex.py | 2 +- tests/test_builders/test_build_warnings.py | 4 +-- tests/test_directives/test_directive_code.py | 28 +++++++++---------- .../test_directive_object_description.py | 4 +-- tests/test_domains/test_domain_cpp.py | 14 +++++----- tests/test_domains/test_domain_js.py | 4 +-- tests/test_domains/test_domain_py.py | 4 +-- tests/test_extensions/test_ext_apidoc.py | 14 ++++++---- tests/test_extensions/test_ext_autosummary.py | 5 ++-- tests/test_extensions/test_ext_ifconfig.py | 4 +-- tests/test_extensions/test_ext_viewcode.py | 4 +-- tests/test_intl/test_intl.py | 3 +- 19 files changed, 80 insertions(+), 75 deletions(-) diff --git a/sphinx/domains/c/_parser.py b/sphinx/domains/c/_parser.py index 42211988414..1d29c60832e 100644 --- a/sphinx/domains/c/_parser.py +++ b/sphinx/domains/c/_parser.py @@ -495,9 +495,11 @@ def _parse_nested_name(self) -> ASTNestedName: self.fail("Expected identifier in nested name, " "got keyword: %s" % identifier) if self.matched_text in self.config.c_extra_keywords: - msg = "Expected identifier, got user-defined keyword: %s." \ - + " Remove it from c_extra_keywords to allow it as identifier.\n" \ - + "Currently c_extra_keywords is %s." + msg = ( + 'Expected identifier, got user-defined keyword: %s.' + ' Remove it from c_extra_keywords to allow it as identifier.\n' + 'Currently c_extra_keywords is %s.' + ) self.fail(msg % (self.matched_text, str(self.config.c_extra_keywords))) ident = ASTIdentifier(identifier) @@ -670,9 +672,11 @@ def _parse_declarator_name_suffix( self.fail("Expected identifier, " "got keyword: %s" % self.matched_text) if self.matched_text in self.config.c_extra_keywords: - msg = "Expected identifier, got user-defined keyword: %s." \ - + " Remove it from c_extra_keywords to allow it as identifier.\n" \ - + "Currently c_extra_keywords is %s." + msg = ( + 'Expected identifier, got user-defined keyword: %s. ' + 'Remove it from c_extra_keywords to allow it as identifier.\n' + 'Currently c_extra_keywords is %s.' + ) self.fail(msg % (self.matched_text, str(self.config.c_extra_keywords))) identifier = ASTIdentifier(self.matched_text) diff --git a/sphinx/domains/cpp/_parser.py b/sphinx/domains/cpp/_parser.py index 452e4c9c8a7..d0d70221a45 100644 --- a/sphinx/domains/cpp/_parser.py +++ b/sphinx/domains/cpp/_parser.py @@ -1263,7 +1263,7 @@ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimpl if self.skip_string('('): expr = self._parse_constant_expression(inTemplate=False) if not expr: - self.fail("Expected constant expression after '('" + + self.fail("Expected constant expression after '('" " in explicit specifier.") self.skip_ws() if not self.skip_string(')'): @@ -1972,13 +1972,14 @@ def _check_template_consistency(self, nestedName: ASTNestedName, if numArgs > numParams: numExtra = numArgs - numParams if not fullSpecShorthand and not isMemberInstantiation: - msg = "Too many template argument lists compared to parameter" \ - " lists. Argument lists: %d, Parameter lists: %d," \ - " Extra empty parameters lists prepended: %d." \ - % (numArgs, numParams, numExtra) - msg += " Declaration:\n\t" + msg = ( + f'Too many template argument lists compared to parameter lists. ' + f'Argument lists: {numArgs:d}, Parameter lists: {numParams:d}, ' + f'Extra empty parameters lists prepended: {numExtra:d}. ' + 'Declaration:\n\t' + ) if templatePrefix: - msg += "%s\n\t" % templatePrefix + msg += f"{templatePrefix}\n\t" msg += str(nestedName) self.warn(msg) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 077f58624d2..e08c0b1e91c 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -394,7 +394,7 @@ def get_parser() -> argparse.ArgumentParser: 'exclude_pattern', nargs='*', help=__( - 'fnmatch-style file and/or directory patterns ' 'to exclude from generation' + 'fnmatch-style file and/or directory patterns to exclude from generation' ), ) @@ -419,7 +419,7 @@ def get_parser() -> argparse.ArgumentParser: dest='maxdepth', type=int, default=4, - help=__('maximum depth of submodules to show in the TOC ' '(default: 4)'), + help=__('maximum depth of submodules to show in the TOC (default: 4)'), ) parser.add_argument( '-f', @@ -435,8 +435,7 @@ def get_parser() -> argparse.ArgumentParser: dest='followlinks', default=False, help=__( - 'follow symbolic links. Powerful when combined ' - 'with collective.recipe.omelette.' + 'follow symbolic links. Powerful when combined with collective.recipe.omelette.' ), ) parser.add_argument( @@ -490,15 +489,14 @@ def get_parser() -> argparse.ArgumentParser: '--module-first', action='store_true', dest='modulefirst', - help=__('put module documentation before submodule ' 'documentation'), + help=__('put module documentation before submodule documentation'), ) parser.add_argument( '--implicit-namespaces', action='store_true', dest='implicit_namespaces', help=__( - 'interpret module paths according to PEP-0420 ' - 'implicit namespaces specification' + 'interpret module paths according to PEP-0420 implicit namespaces specification' ), ) parser.add_argument( @@ -559,7 +557,7 @@ def get_parser() -> argparse.ArgumentParser: action='store', dest='release', help=__( - 'project release, used when --full is given, ' 'defaults to --doc-version' + 'project release, used when --full is given, defaults to --doc-version' ), ) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index eab9d00b17a..bed3e5b8a37 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -803,7 +803,7 @@ def get_parser() -> argparse.ArgumentParser: action='store', dest='suffix', default='rst', - help=__('default suffix for files (default: ' '%(default)s)'), + help=__('default suffix for files (default: %(default)s)'), ) parser.add_argument( '-t', @@ -811,7 +811,7 @@ def get_parser() -> argparse.ArgumentParser: action='store', dest='templates', default=None, - help=__('custom template directory (default: ' '%(default)s)'), + help=__('custom template directory (default: %(default)s)'), ) parser.add_argument( '-i', @@ -819,7 +819,7 @@ def get_parser() -> argparse.ArgumentParser: action='store_true', dest='imported_members', default=False, - help=__('document imported members (default: ' '%(default)s)'), + help=__('document imported members (default: %(default)s)'), ) parser.add_argument( '-a', diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index f7ce3beaa65..5ecc1670959 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -455,7 +455,7 @@ def write_py_coverage(self) -> None: if self.app.quiet or self.app.warningiserror: for meth in methods: logger.warning( - __('undocumented python method:' + + __('undocumented python method:' ' %s :: %s :: %s'), name, class_name, meth) else: diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index 35e1a086abb..8b67836764a 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -202,7 +202,7 @@ def list_replace_or_append(lst: list[N], old: N, new: N) -> None: old_foot_refs = list(is_autofootnote_ref.findall(self.node)) new_foot_refs = list(is_autofootnote_ref.findall(self.patch)) self.compare_references(old_foot_refs, new_foot_refs, - __('inconsistent footnote references in translated message.' + + __('inconsistent footnote references in translated message.' ' original: {0}, translated: {1}')) old_foot_namerefs: dict[str, list[nodes.footnote_reference]] = {} for r in old_foot_refs: @@ -242,7 +242,7 @@ def update_refnamed_references(self) -> None: old_refs = list(is_refnamed_ref.findall(self.node)) new_refs = list(is_refnamed_ref.findall(self.patch)) self.compare_references(old_refs, new_refs, - __('inconsistent references in translated message.' + + __('inconsistent references in translated message.' ' original: {0}, translated: {1}')) old_ref_names = [r['refname'] for r in old_refs] new_ref_names = [r['refname'] for r in new_refs] @@ -267,7 +267,7 @@ def update_refnamed_footnote_references(self) -> None: new_foot_refs = list(is_refnamed_footnote_ref.findall(self.patch)) refname_ids_map: dict[str, list[str]] = {} self.compare_references(old_foot_refs, new_foot_refs, - __('inconsistent footnote references in translated message.' + + __('inconsistent footnote references in translated message.' ' original: {0}, translated: {1}')) for oldf in old_foot_refs: refname_ids_map.setdefault(oldf["refname"], []).append(oldf["ids"]) @@ -282,7 +282,7 @@ def update_citation_references(self) -> None: old_cite_refs = list(is_citation_ref.findall(self.node)) new_cite_refs = list(is_citation_ref.findall(self.patch)) self.compare_references(old_cite_refs, new_cite_refs, - __('inconsistent citation references in translated message.' + + __('inconsistent citation references in translated message.' ' original: {0}, translated: {1}')) refname_ids_map: dict[str, list[str]] = {} for oldc in old_cite_refs: @@ -299,7 +299,7 @@ def update_pending_xrefs(self) -> None: old_xrefs = [*self.node.findall(addnodes.pending_xref)] new_xrefs = [*self.patch.findall(addnodes.pending_xref)] self.compare_references(old_xrefs, new_xrefs, - __('inconsistent term references in translated message.' + + __('inconsistent term references in translated message.' ' original: {0}, translated: {1}')) xref_reftarget_map: dict[tuple[str, str, str] | None, dict[str, Any]] = {} diff --git a/tests/test_builders/test_build_html_code.py b/tests/test_builders/test_build_html_code.py index f07eb97e4d4..6459357ef0f 100644 --- a/tests/test_builders/test_build_html_code.py +++ b/tests/test_builders/test_build_html_code.py @@ -41,6 +41,6 @@ def test_html_code_role(app): 'pass') assert ('

Inline ' + common_content + ' code block

') in content - assert ('
' + + assert ('
' '
' +
             common_content) in content
diff --git a/tests/test_builders/test_build_latex.py b/tests/test_builders/test_build_latex.py
index c2bd2d970d1..46d597ea222 100644
--- a/tests/test_builders/test_build_latex.py
+++ b/tests/test_builders/test_build_latex.py
@@ -1698,7 +1698,7 @@ def test_latex_code_role(app):
         r'\PYG{k}{pass}')
     assert (r'Inline \sphinxcode{\sphinxupquote{%' + '\n' +
             common_content + '%\n}} code block') in content
-    assert (r'\begin{sphinxVerbatim}[commandchars=\\\{\}]' +
+    assert (r'\begin{sphinxVerbatim}[commandchars=\\\{\}]'
             '\n' + common_content + '\n' + r'\end{sphinxVerbatim}') in content
 
 
diff --git a/tests/test_builders/test_build_warnings.py b/tests/test_builders/test_build_warnings.py
index 0ccade75e07..8a0efbf40ad 100644
--- a/tests/test_builders/test_build_warnings.py
+++ b/tests/test_builders/test_build_warnings.py
@@ -45,8 +45,8 @@ def _check_warnings(expected_warnings: str, warning: str) -> None:
     warnings = strip_colors(re.sub(re.escape(os.sep) + '{1,2}', '/', warning))
     assert re.match(f'{expected_warnings}$', warnings), (
         "Warnings don't match:\n"
-        + f'--- Expected (regex):\n{expected_warnings}\n'
-        + f'--- Got:\n{warnings}'
+        f'--- Expected (regex):\n{expected_warnings}\n'
+        f'--- Got:\n{warnings}'
     )
     sys.modules.pop('autodoc_fodder', None)
 
diff --git a/tests/test_directives/test_directive_code.py b/tests/test_directives/test_directive_code.py
index 3f65bf58646..a6c5d59bbf7 100644
--- a/tests/test_directives/test_directive_code.py
+++ b/tests/test_directives/test_directive_code.py
@@ -302,8 +302,8 @@ def test_code_block(app):
     assert len(code_block) > 0
     actual = code_block[0].text
     expect = (
-        "    def ruby?\n" +
-        "        false\n" +
+        "    def ruby?\n"
+        "        false\n"
         "    end"
     )
     assert actual == expect
@@ -333,8 +333,8 @@ def test_code_block_caption_latex(app):
     latex = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
     caption = '\\sphinxSetupCaptionForVerbatim{caption \\sphinxstyleemphasis{test} rb}'
     label = '\\def\\sphinxLiteralBlockLabel{\\label{\\detokenize{caption:id1}}}'
-    link = '\\hyperref[\\detokenize{caption:name-test-rb}]' \
-           '{Listing \\ref{\\detokenize{caption:name-test-rb}}}'
+    link = ('\\hyperref[\\detokenize{caption:name-test-rb}]'
+            '{Listing \\ref{\\detokenize{caption:name-test-rb}}}')
     assert caption in latex
     assert label in latex
     assert link in latex
@@ -345,12 +345,12 @@ def test_code_block_namedlink_latex(app):
     app.build(force_all=True)
     latex = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
     label1 = '\\def\\sphinxLiteralBlockLabel{\\label{\\detokenize{caption:name-test-rb}}}'
-    link1 = '\\hyperref[\\detokenize{caption:name-test-rb}]'\
-            '{\\sphinxcrossref{\\DUrole{std,std-ref}{Ruby}}'
+    link1 = ('\\hyperref[\\detokenize{caption:name-test-rb}]'
+             '{\\sphinxcrossref{\\DUrole{std,std-ref}{Ruby}}')
     label2 = ('\\def\\sphinxLiteralBlockLabel'
               '{\\label{\\detokenize{namedblocks:some-ruby-code}}}')
-    link2 = '\\hyperref[\\detokenize{namedblocks:some-ruby-code}]'\
-            '{\\sphinxcrossref{\\DUrole{std,std-ref}{the ruby code}}}'
+    link2 = ('\\hyperref[\\detokenize{namedblocks:some-ruby-code}]'
+             '{\\sphinxcrossref{\\DUrole{std,std-ref}{the ruby code}}}')
     assert label1 in latex
     assert link1 in latex
     assert label2 in latex
@@ -453,8 +453,8 @@ def test_literalinclude_caption_latex(app):
     latex = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
     caption = '\\sphinxSetupCaptionForVerbatim{caption \\sphinxstylestrong{test} py}'
     label = '\\def\\sphinxLiteralBlockLabel{\\label{\\detokenize{caption:id2}}}'
-    link = '\\hyperref[\\detokenize{caption:name-test-py}]' \
-           '{Listing \\ref{\\detokenize{caption:name-test-py}}}'
+    link = ('\\hyperref[\\detokenize{caption:name-test-py}]'
+            '{Listing \\ref{\\detokenize{caption:name-test-py}}}')
     assert caption in latex
     assert label in latex
     assert link in latex
@@ -465,12 +465,12 @@ def test_literalinclude_namedlink_latex(app):
     app.build(filenames='index')
     latex = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
     label1 = '\\def\\sphinxLiteralBlockLabel{\\label{\\detokenize{caption:name-test-py}}}'
-    link1 = '\\hyperref[\\detokenize{caption:name-test-py}]'\
-            '{\\sphinxcrossref{\\DUrole{std,std-ref}{Python}}'
+    link1 = ('\\hyperref[\\detokenize{caption:name-test-py}]'
+             '{\\sphinxcrossref{\\DUrole{std,std-ref}{Python}}')
     label2 = ('\\def\\sphinxLiteralBlockLabel'
               '{\\label{\\detokenize{namedblocks:some-python-code}}}')
-    link2 = '\\hyperref[\\detokenize{namedblocks:some-python-code}]'\
-            '{\\sphinxcrossref{\\DUrole{std,std-ref}{the python code}}}'
+    link2 = ('\\hyperref[\\detokenize{namedblocks:some-python-code}]'
+             '{\\sphinxcrossref{\\DUrole{std,std-ref}{the python code}}}')
     assert label1 in latex
     assert link1 in latex
     assert label2 in latex
diff --git a/tests/test_directives/test_directive_object_description.py b/tests/test_directives/test_directive_object_description.py
index 8808c3580a8..b048e8b5890 100644
--- a/tests/test_directives/test_directive_object_description.py
+++ b/tests/test_directives/test_directive_object_description.py
@@ -55,8 +55,8 @@ def test_object_description_sections(app):
 
 
 def test_object_description_content_line_number(app):
-    text = (".. py:function:: foo(bar)\n" +
-            "\n" +
+    text = (".. py:function:: foo(bar)\n"
+            "\n"
             "   Some link here: :ref:`abc`\n")
     doc = restructuredtext.parse(app, text)
     xrefs = list(doc.findall(condition=addnodes.pending_xref))
diff --git a/tests/test_domains/test_domain_cpp.py b/tests/test_domains/test_domain_cpp.py
index 64c4bd2ac0a..114726cebed 100644
--- a/tests/test_domains/test_domain_cpp.py
+++ b/tests/test_domains/test_domain_cpp.py
@@ -485,8 +485,8 @@ def test_domain_cpp_ast_function_definitions():
     check('function', 'bool namespaced::theclass::method(arg1, arg2)',
           {1: "namespaced::theclass::method__arg1.arg2",
            2: "N10namespaced8theclass6methodE4arg14arg2"})
-    x = 'std::vector> &module::test(register int ' \
-        'foo, bar, std::string baz = "foobar, blah, bleh") const = 0'
+    x = ('std::vector> &module::test(register int '
+         'foo, bar, std::string baz = "foobar, blah, bleh") const = 0')
     check('function', x, {1: "module::test__i.bar.ssC",
                           2: "NK6module4testEi3barNSt6stringE"})
     check('function', 'void f(std::pair)',
@@ -557,8 +557,8 @@ def test_domain_cpp_ast_function_definitions():
     check('function', 'MyClass::pointer MyClass::operator->()',
           {1: "MyClass::pointer-operator", 2: "N7MyClassptEv"})
 
-    x = 'std::vector> &module::test(register int ' \
-        'foo, bar[n], std::string baz = "foobar, blah, bleh") const = 0'
+    x = ('std::vector> &module::test(register int '
+         'foo, bar[n], std::string baz = "foobar, blah, bleh") const = 0')
     check('function', x, {1: "module::test__i.barA.ssC",
                           2: "NK6module4testEiAn_3barNSt6stringE",
                           3: "NK6module4testEiA1n_3barNSt6stringE"})
@@ -920,12 +920,12 @@ def test_domain_cpp_ast_requires_clauses():
     check('function', 'template requires A && B || C and D void f()',
           {4: 'I0EIQooaa1A1Baa1C1DE1fvv'})
     check('function',
-          'template requires R ' +
-          'template requires S ' +
+          'template requires R '
+          'template requires S '
           'void A::f() requires B',
           {4: 'I0EIQ1RI1TEEI0EIQaa1SI1TE1BEN1A1fEvv'})
     check('function',
-          'template requires R typename X> ' +
+          'template requires R typename X> '
           'void f()',
           {2: 'II0EIQ1RI1TEE0E1fv', 4: 'II0EIQ1RI1TEE0E1fvv'})
     check('type',
diff --git a/tests/test_domains/test_domain_js.py b/tests/test_domains/test_domain_js.py
index a7d093060be..2078c6a56ba 100644
--- a/tests/test_domains/test_domain_js.py
+++ b/tests/test_domains/test_domain_js.py
@@ -234,8 +234,8 @@ def test_no_index_entry(app):
 
 
 def test_module_content_line_number(app):
-    text = (".. js:module:: foo\n" +
-            "\n" +
+    text = (".. js:module:: foo\n"
+            "\n"
             "   Some link here: :ref:`abc`\n")
     doc = restructuredtext.parse(app, text)
     xrefs = list(doc.findall(condition=addnodes.pending_xref))
diff --git a/tests/test_domains/test_domain_py.py b/tests/test_domains/test_domain_py.py
index 4362469f838..69cae68529b 100644
--- a/tests/test_domains/test_domain_py.py
+++ b/tests/test_domains/test_domain_py.py
@@ -691,8 +691,8 @@ def test_domain_py_python_maximum_signature_line_length_in_text(app):
 
 
 def test_module_content_line_number(app):
-    text = (".. py:module:: foo\n" +
-            "\n" +
+    text = (".. py:module:: foo\n"
+            "\n"
             "   Some link here: :ref:`abc`\n")
     doc = restructuredtext.parse(app, text)
     xrefs = list(doc.findall(condition=addnodes.pending_xref))
diff --git a/tests/test_extensions/test_ext_apidoc.py b/tests/test_extensions/test_ext_apidoc.py
index 0d1b519cef6..b0ea2e34ccd 100644
--- a/tests/test_extensions/test_ext_apidoc.py
+++ b/tests/test_extensions/test_ext_apidoc.py
@@ -322,9 +322,10 @@ def test_toc_all_references_should_exist_pep420_enabled(make_app, apidoc):
         if not (outdir / filename).is_file():
             missing_files.append(filename)
 
-    assert len(missing_files) == 0, \
-        'File(s) referenced in TOC not found: {}\n' \
-        'TOC:\n{}'.format(", ".join(missing_files), toc)
+    all_missing = ', '.join(missing_files)
+    assert len(missing_files) == 0, (
+        f'File(s) referenced in TOC not found: {all_missing}\nTOC:\n{toc}'
+    )
 
 
 @pytest.mark.apidoc(
@@ -352,9 +353,10 @@ def test_toc_all_references_should_exist_pep420_disabled(make_app, apidoc):
         if not (outdir / filename).is_file():
             missing_files.append(filename)
 
-    assert len(missing_files) == 0, \
-        'File(s) referenced in TOC not found: {}\n' \
-        'TOC:\n{}'.format(", ".join(missing_files), toc)
+    all_missing = ', '.join(missing_files)
+    assert len(missing_files) == 0, (
+        f'File(s) referenced in TOC not found: {all_missing}\nTOC:\n{toc}'
+    )
 
 
 def extract_toc(path):
diff --git a/tests/test_extensions/test_ext_autosummary.py b/tests/test_extensions/test_ext_autosummary.py
index 2f8bb946713..14fc4cf6505 100644
--- a/tests/test_extensions/test_ext_autosummary.py
+++ b/tests/test_extensions/test_ext_autosummary.py
@@ -186,8 +186,9 @@ def handler(app, what, name, obj, options, lines):
         'C.C2': 'This is a nested inner class docstring',
     }
     for key, expected in expected_values.items():
-        assert autosummary_items[key][2] == expected, 'Summary for %s was %r -'\
-            ' expected %r' % (key, autosummary_items[key], expected)
+        assert autosummary_items[key][2] == expected, (
+            f'Summary for {key} was {autosummary_items[key]!r} - expected {expected!r}'
+        )
 
     # check an item in detail
     assert 'func' in autosummary_items
diff --git a/tests/test_extensions/test_ext_ifconfig.py b/tests/test_extensions/test_ext_ifconfig.py
index e1e2f0a735b..24986789b7f 100644
--- a/tests/test_extensions/test_ext_ifconfig.py
+++ b/tests/test_extensions/test_ext_ifconfig.py
@@ -17,8 +17,8 @@ def test_ifconfig(app):
 
 def test_ifconfig_content_line_number(app):
     app.setup_extension("sphinx.ext.ifconfig")
-    text = (".. ifconfig:: confval1\n" +
-            "\n" +
+    text = (".. ifconfig:: confval1\n"
+            "\n"
             "   Some link here: :ref:`abc`\n")
     doc = restructuredtext.parse(app, text)
     xrefs = list(doc.findall(condition=addnodes.pending_xref))
diff --git a/tests/test_extensions/test_ext_viewcode.py b/tests/test_extensions/test_ext_viewcode.py
index 2bb2116c773..ce5abeb5117 100644
--- a/tests/test_extensions/test_ext_viewcode.py
+++ b/tests/test_extensions/test_ext_viewcode.py
@@ -15,7 +15,7 @@
 def check_viewcode_output(app: SphinxTestApp) -> str:
     warnings = re.sub(r'\\+', '/', app.warning.getvalue())
     assert re.findall(
-        r"index.rst:\d+: WARNING: Object named 'func1' not found in include " +
+        r"index.rst:\d+: WARNING: Object named 'func1' not found in include "
         r"file .*/spam/__init__.py'",
         warnings,
     )
@@ -131,7 +131,7 @@ def find_source(app, modname):
 
     warnings = re.sub(r'\\+', '/', app.warning.getvalue())
     assert re.findall(
-        r"index.rst:\d+: WARNING: Object named 'func1' not found in include " +
+        r"index.rst:\d+: WARNING: Object named 'func1' not found in include "
         r"file .*/not_a_package/__init__.py'",
         warnings,
     )
diff --git a/tests/test_intl/test_intl.py b/tests/test_intl/test_intl.py
index 8c787e669d8..6fc5f448f46 100644
--- a/tests/test_intl/test_intl.py
+++ b/tests/test_intl/test_intl.py
@@ -1307,8 +1307,7 @@ def test_xml_label_targets(app):
     assert_elem(
         para3[0],
         ['X', 'bridge label',
-         'IS NOT TRANSLATABLE BUT LINKED TO TRANSLATED ' +
-         'SECTION TITLE.'],
+         'IS NOT TRANSLATABLE BUT LINKED TO TRANSLATED SECTION TITLE.'],
         ['label-bridged-target-section'])
     assert_elem(
         para3[1],

From d03156e07849173385223861ad1e4e7d57ebf8cf Mon Sep 17 00:00:00 2001
From: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Date: Sun, 11 Aug 2024 14:58:56 +0100
Subject: [PATCH 08/24] Format ``tests/`` (#12760)

---
 tests/conftest.py                             |    7 +-
 .../target/abstractmethods.py                 |    2 +-
 .../roots/test-ext-autodoc/target/callable.py |    2 +-
 .../roots/test-ext-autodoc/target/methods.py  |    2 +-
 .../autosummary_class_module.py               |    2 +-
 tests/test_application.py                     |   64 +-
 tests/test_builders/test_build.py             |   75 +-
 tests/test_builders/test_build_changes.py     |   13 +-
 tests/test_builders/test_build_dirhtml.py     |   23 +-
 tests/test_builders/test_build_epub.py        |  318 ++-
 tests/test_builders/test_build_gettext.py     |  170 +-
 tests/test_builders/test_build_html.py        |  522 ++--
 .../test_builders/test_build_html_5_output.py |  719 ++++--
 tests/test_builders/test_build_html_assets.py |   47 +-
 tests/test_builders/test_build_html_code.py   |   41 +-
 .../test_builders/test_build_html_download.py |   65 +-
 .../test_build_html_highlight.py              |   93 +-
 tests/test_builders/test_build_html_image.py  |   40 +-
 tests/test_builders/test_build_html_maths.py  |   54 +-
 tests/test_builders/test_build_html_numfig.py | 1392 ++++++++---
 .../test_builders/test_build_html_tocdepth.py |  166 +-
 tests/test_builders/test_build_latex.py       | 1647 ++++++++-----
 tests/test_builders/test_build_linkcheck.py   |  703 ++++--
 tests/test_builders/test_build_manpage.py     |   33 +-
 tests/test_builders/test_build_texinfo.py     |   48 +-
 tests/test_builders/test_build_text.py        |  240 +-
 tests/test_builders/test_build_warnings.py    |   42 +-
 tests/test_builders/test_builder.py           |   12 +-
 tests/test_builders/xpath_data.py             |    2 +-
 tests/test_builders/xpath_util.py             |   10 +-
 tests/test_config/test_config.py              |  281 ++-
 tests/test_config/test_correct_year.py        |    2 +-
 tests/test_directives/test_directive_code.py  |  305 +--
 .../test_directive_object_description.py      |    4 +-
 tests/test_directives/test_directive_only.py  |   21 +-
 .../test_directives/test_directive_option.py  |   49 +-
 tests/test_directives/test_directive_other.py |  176 +-
 tests/test_directives/test_directive_patch.py |  130 +-
 .../test_directives_no_typesetting.py         |  219 +-
 tests/test_domains/test_domain_c.py           |  958 ++++---
 tests/test_domains/test_domain_cpp.py         | 2192 +++++++++++------
 tests/test_domains/test_domain_js.py          |  687 ++++--
 tests/test_domains/test_domain_py.py          | 1591 +++++++-----
 .../test_domains/test_domain_py_canonical.py  |   74 +-
 tests/test_domains/test_domain_py_fields.py   |  752 ++++--
 .../test_domains/test_domain_py_pyfunction.py |  986 +++++---
 tests/test_domains/test_domain_py_pyobject.py | 1272 +++++++---
 tests/test_domains/test_domain_rst.py         |  287 ++-
 tests/test_domains/test_domain_std.py         |  652 +++--
 tests/test_environment/test_environment.py    |   63 +-
 .../test_environment_indexentries.py          |  292 ++-
 .../test_environment_toctree.py               | 1026 +++++---
 tests/test_errors.py                          |    4 +-
 tests/test_events.py                          |    6 +-
 tests/test_extensions/test_ext_apidoc.py      |  466 ++--
 tests/test_extensions/test_ext_autodoc.py     |  553 +++--
 .../test_ext_autodoc_autoclass.py             |   69 +-
 .../test_ext_autodoc_automodule.py            |   46 +-
 .../test_ext_autodoc_autoproperty.py          |   12 +-
 .../test_ext_autodoc_configs.py               |  511 ++--
 .../test_ext_autodoc_events.py                |   15 +-
 .../test_extensions/test_ext_autodoc_mock.py  |   18 +-
 .../test_ext_autodoc_preserve_defaults.py     |   24 +-
 .../test_ext_autodoc_private_members.py       |   25 +-
 .../test_ext_autosectionlabel.py              |   71 +-
 tests/test_extensions/test_ext_autosummary.py |  641 +++--
 .../test_ext_autosummary_imports.py           |   51 +-
 tests/test_extensions/test_ext_coverage.py    |   48 +-
 tests/test_extensions/test_ext_doctest.py     |   52 +-
 tests/test_extensions/test_ext_duration.py    |    7 +-
 tests/test_extensions/test_ext_extlinks.py    |   32 +-
 tests/test_extensions/test_ext_githubpages.py |   14 +-
 tests/test_extensions/test_ext_graphviz.py    |  155 +-
 tests/test_extensions/test_ext_ifconfig.py    |    6 +-
 .../test_extensions/test_ext_imgconverter.py  |    6 +-
 .../test_ext_inheritance_diagram.py           |  119 +-
 tests/test_extensions/test_ext_intersphinx.py |  209 +-
 .../test_ext_intersphinx_cache.py             |   36 +-
 tests/test_extensions/test_ext_math.py        |  432 ++--
 tests/test_extensions/test_ext_napoleon.py    |  186 +-
 .../test_ext_napoleon_docstring.py            | 1157 +++++----
 tests/test_extensions/test_ext_todo.py        |   77 +-
 tests/test_extensions/test_ext_viewcode.py    |   62 +-
 tests/test_extensions/test_extension.py       |    8 +-
 tests/test_highlighting.py                    |   50 +-
 tests/test_intl/test_catalogs.py              |   31 +-
 tests/test_intl/test_intl.py                  |  974 +++++---
 tests/test_intl/test_locale.py                |    4 +-
 tests/test_markup/test_markup.py              |  722 +++---
 tests/test_markup/test_metadata.py            |   22 +-
 tests/test_markup/test_parser.py              |   42 +-
 tests/test_markup/test_smartquotes.py         |   70 +-
 tests/test_project.py                         |   34 +-
 tests/test_pycode/test_pycode.py              |  200 +-
 tests/test_pycode/test_pycode_ast.py          |  107 +-
 tests/test_pycode/test_pycode_parser.py       |  775 +++---
 tests/test_quickstart.py                      |   33 +-
 tests/test_roles.py                           |   76 +-
 tests/test_search.py                          |  145 +-
 tests/test_theming/test_html_theme.py         |   16 +-
 tests/test_theming/test_templating.py         |   12 +-
 tests/test_theming/test_theming.py            |   19 +-
 tests/test_toctree.py                         |   12 +-
 .../test_transforms_move_module_targets.py    |   39 +-
 .../test_transforms_post_transforms.py        |   97 +-
 .../test_transforms_post_transforms_code.py   |    7 +-
 .../test_transforms_reorder_nodes.py          |  165 +-
 .../test_unreferenced_footnotes.py            |   18 +-
 tests/test_util/intersphinx_data.py           |   22 +-
 tests/test_util/test_util.py                  |   33 +-
 tests/test_util/test_util_display.py          |   18 +-
 tests/test_util/test_util_docstrings.py       |   66 +-
 tests/test_util/test_util_docutils.py         |    2 +-
 .../test_util_docutils_sphinx_directive.py    |    8 +-
 tests/test_util/test_util_fileutil.py         |   43 +-
 tests/test_util/test_util_i18n.py             |  103 +-
 tests/test_util/test_util_images.py           |   29 +-
 tests/test_util/test_util_inspect.py          |  276 ++-
 tests/test_util/test_util_inventory.py        |   53 +-
 tests/test_util/test_util_logging.py          |   34 +-
 tests/test_util/test_util_matching.py         |  236 +-
 tests/test_util/test_util_nodes.py            |   42 +-
 tests/test_util/test_util_rst.py              |  191 +-
 tests/test_util/test_util_template.py         |    6 +-
 tests/test_util/test_util_typing.py           |  980 +++++---
 tests/test_util/typing_test_data.py           |    4 +-
 tests/test_writers/test_docutilsconf.py       |   25 +-
 tests/utils.py                                |    4 +-
 128 files changed, 19011 insertions(+), 10525 deletions(-)

diff --git a/tests/conftest.py b/tests/conftest.py
index 391cb4dc562..6e3b83b1397 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -19,7 +19,8 @@
 
 
 def _init_console(
-    locale_dir: str | None = sphinx.locale._LOCALE_DIR, catalog: str = 'sphinx',
+    locale_dir: str | None = sphinx.locale._LOCALE_DIR,
+    catalog: str = 'sphinx',
 ) -> tuple[gettext.NullTranslations, bool]:
     """Monkeypatch ``init_console`` to skip its action.
 
@@ -46,9 +47,9 @@ def rootdir() -> Path:
 
 
 def pytest_report_header(config: pytest.Config) -> str:
-    header = f"libraries: Sphinx-{sphinx.__display_version__}, docutils-{docutils.__version__}"
+    header = f'libraries: Sphinx-{sphinx.__display_version__}, docutils-{docutils.__version__}'
     if hasattr(config, '_tmp_path_factory'):
-        header += f"\nbase tmp_path: {config._tmp_path_factory.getbasetemp()}"
+        header += f'\nbase tmp_path: {config._tmp_path_factory.getbasetemp()}'
     return header
 
 
diff --git a/tests/roots/test-ext-autodoc/target/abstractmethods.py b/tests/roots/test-ext-autodoc/target/abstractmethods.py
index a4396d5c93e..d860495e69d 100644
--- a/tests/roots/test-ext-autodoc/target/abstractmethods.py
+++ b/tests/roots/test-ext-autodoc/target/abstractmethods.py
@@ -1,7 +1,7 @@
 from abc import abstractmethod
 
 
-class Base():
+class Base:
     def meth(self):
         pass
 
diff --git a/tests/roots/test-ext-autodoc/target/callable.py b/tests/roots/test-ext-autodoc/target/callable.py
index 6fcd5053ee0..93a2c178f7b 100644
--- a/tests/roots/test-ext-autodoc/target/callable.py
+++ b/tests/roots/test-ext-autodoc/target/callable.py
@@ -1,4 +1,4 @@
-class Callable():
+class Callable:
     """A callable object that behaves like a function."""
 
     def __call__(self, arg1, arg2, **kwargs):
diff --git a/tests/roots/test-ext-autodoc/target/methods.py b/tests/roots/test-ext-autodoc/target/methods.py
index ad5a6a952ca..4900f7989d7 100644
--- a/tests/roots/test-ext-autodoc/target/methods.py
+++ b/tests/roots/test-ext-autodoc/target/methods.py
@@ -1,7 +1,7 @@
 from functools import partialmethod
 
 
-class Base():
+class Base:
     def meth(self):
         pass
 
diff --git a/tests/roots/test-ext-autosummary/autosummary_class_module.py b/tests/roots/test-ext-autosummary/autosummary_class_module.py
index f13de17032f..2b1f40419d6 100644
--- a/tests/roots/test-ext-autosummary/autosummary_class_module.py
+++ b/tests/roots/test-ext-autosummary/autosummary_class_module.py
@@ -1,2 +1,2 @@
-class Class():
+class Class:
   pass
diff --git a/tests/test_application.py b/tests/test_application.py
index ee7e850e7c2..d30a9b12463 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -1,4 +1,5 @@
 """Test the Sphinx class."""
+
 from __future__ import annotations
 
 import shutil
@@ -51,26 +52,27 @@ def test_instantiation(
 def test_events(app):
     def empty():
         pass
+
     with pytest.raises(ExtensionError) as excinfo:
-        app.connect("invalid", empty)
-    assert "Unknown event name: invalid" in str(excinfo.value)
+        app.connect('invalid', empty)
+    assert 'Unknown event name: invalid' in str(excinfo.value)
 
-    app.add_event("my_event")
+    app.add_event('my_event')
     with pytest.raises(ExtensionError) as excinfo:
-        app.add_event("my_event")
+        app.add_event('my_event')
     assert "Event 'my_event' already present" in str(excinfo.value)
 
     def mock_callback(a_app, *args):
         assert a_app is app
         assert emit_args == args
-        return "ret"
-    emit_args = (1, 3, "string")
-    listener_id = app.connect("my_event", mock_callback)
-    assert app.emit("my_event", *emit_args) == ["ret"], "Callback not called"
+        return 'ret'
+
+    emit_args = (1, 3, 'string')
+    listener_id = app.connect('my_event', mock_callback)
+    assert app.emit('my_event', *emit_args) == ['ret'], 'Callback not called'
 
     app.disconnect(listener_id)
-    assert app.emit("my_event", *emit_args) == [], \
-        "Callback called when disconnected"
+    assert app.emit('my_event', *emit_args) == [], 'Callback called when disconnected'
 
 
 def test_emit_with_nonascii_name_node(app):
@@ -121,14 +123,18 @@ def test_add_is_parallel_allowed(app):
     app.setup_extension('write_parallel')
     assert app.is_parallel_allowed('read') is False
     assert app.is_parallel_allowed('write') is True
-    assert ("the write_parallel extension does not declare if it is safe "
-            "for parallel reading, assuming it isn't - please ") in app.warning.getvalue()
+    assert (
+        'the write_parallel extension does not declare if it is safe '
+        "for parallel reading, assuming it isn't - please "
+    ) in app.warning.getvalue()
     app.extensions.pop('write_parallel')
     app.warning.truncate(0)  # reset warnings
 
     app.setup_extension('read_serial')
     assert app.is_parallel_allowed('read') is False
-    assert "the read_serial extension is not safe for parallel reading" in app.warning.getvalue()
+    assert (
+        'the read_serial extension is not safe for parallel reading'
+    ) in app.warning.getvalue()
     app.warning.truncate(0)  # reset warnings
     assert app.is_parallel_allowed('write') is True
     assert app.warning.getvalue() == ''
@@ -137,8 +143,10 @@ def test_add_is_parallel_allowed(app):
     app.setup_extension('write_serial')
     assert app.is_parallel_allowed('read') is False
     assert app.is_parallel_allowed('write') is False
-    assert ("the write_serial extension does not declare if it is safe "
-            "for parallel reading, assuming it isn't - please ") in app.warning.getvalue()
+    assert (
+        'the write_serial extension does not declare if it is safe '
+        "for parallel reading, assuming it isn't - please "
+    ) in app.warning.getvalue()
     app.extensions.pop('write_serial')
     app.warning.truncate(0)  # reset warnings
 
@@ -146,17 +154,21 @@ def test_add_is_parallel_allowed(app):
 @pytest.mark.sphinx('dummy', testroot='root')
 def test_build_specific(app):
     app.builder.build = Mock()
-    filenames = [app.srcdir / 'index.txt',                      # normal
-                 app.srcdir / 'images',                         # without suffix
-                 app.srcdir / 'notfound.txt',                   # not found
-                 app.srcdir / 'img.png',                        # unknown suffix
-                 '/index.txt',                                  # external file
-                 app.srcdir / 'subdir',                         # directory
-                 app.srcdir / 'subdir/includes.txt',            # file on subdir
-                 app.srcdir / 'subdir/../subdir/excluded.txt']  # not normalized
+    filenames = [
+        app.srcdir / 'index.txt',                      # normal
+        app.srcdir / 'images',                         # without suffix
+        app.srcdir / 'notfound.txt',                   # not found
+        app.srcdir / 'img.png',                        # unknown suffix
+        '/index.txt',                                  # external file
+        app.srcdir / 'subdir',                         # directory
+        app.srcdir / 'subdir/includes.txt',            # file on subdir
+        app.srcdir / 'subdir/../subdir/excluded.txt',  # not normalized
+    ]  # fmt: skip
     app.build(False, filenames)
 
     expected = ['index', 'subdir/includes', 'subdir/excluded']
-    app.builder.build.assert_called_with(expected,
-                                         method='specific',
-                                         summary='3 source files given on command line')
+    app.builder.build.assert_called_with(
+        expected,
+        method='specific',
+        summary='3 source files given on command line',
+    )
diff --git a/tests/test_builders/test_build.py b/tests/test_builders/test_build.py
index 009eb97e86d..5ccef02c943 100644
--- a/tests/test_builders/test_build.py
+++ b/tests/test_builders/test_build.py
@@ -31,35 +31,44 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
         shutil.copytree(rootdir / 'test-root', srcdir)
 
     # add a doc with a non-ASCII file name to the source dir
-    (srcdir / (test_name + '.txt')).write_text("""
+    (srcdir / (test_name + '.txt')).write_text(
+        """
 nonascii file name page
 =======================
-""", encoding='utf8')
+""",
+        encoding='utf8',
+    )
 
     root_doc = srcdir / 'index.txt'
-    root_doc.write_text(root_doc.read_text(encoding='utf8') + f"""
+    root_doc.write_text(
+        root_doc.read_text(encoding='utf8')
+        + f"""
 .. toctree::
 
 {test_name}/{test_name}
-""", encoding='utf8')
+""",
+        encoding='utf8',
+    )
     return srcdir
 
 
 # note: this test skips building docs for some builders because they have independent testcase.
 #       (html, changes, epub, latex, texinfo and manpage)
 @pytest.mark.parametrize(
-    "buildername",
+    'buildername',
     ['dirhtml', 'singlehtml', 'text', 'xml', 'pseudoxml', 'linkcheck'],
 )
-@mock.patch('sphinx.builders.linkcheck.requests.head',
-            side_effect=request_session_head)
+@mock.patch(
+    'sphinx.builders.linkcheck.requests.head',
+    side_effect=request_session_head,
+)
 def test_build_all(requests_head, make_app, nonascii_srcdir, buildername):
     app = make_app(buildername, srcdir=nonascii_srcdir)
     app.build()
 
 
 def test_root_doc_not_found(tmp_path, make_app):
-    (tmp_path / 'conf.py').write_text('', encoding='utf8')
+    (tmp_path / 'conf.py').touch()
     assert os.listdir(tmp_path) == ['conf.py']
 
     app = make_app('dummy', srcdir=tmp_path)
@@ -67,31 +76,31 @@ def test_root_doc_not_found(tmp_path, make_app):
         app.build(force_all=True)  # no index.rst
 
 
-@pytest.mark.sphinx(buildername='text', testroot='circular')
+@pytest.mark.sphinx('text', testroot='circular')
 def test_circular_toctree(app):
     app.build(force_all=True)
     warnings = app.warning.getvalue()
     assert (
-        'circular toctree references detected, ignoring: '
-        'sub <- index <- sub') in warnings
+        'circular toctree references detected, ignoring: sub <- index <- sub'
+    ) in warnings
     assert (
-        'circular toctree references detected, ignoring: '
-        'index <- sub <- index') in warnings
+        'circular toctree references detected, ignoring: index <- sub <- index'
+    ) in warnings
 
 
-@pytest.mark.sphinx(buildername='text', testroot='numbered-circular')
+@pytest.mark.sphinx('text', testroot='numbered-circular')
 def test_numbered_circular_toctree(app):
     app.build(force_all=True)
     warnings = app.warning.getvalue()
     assert (
-        'circular toctree references detected, ignoring: '
-        'sub <- index <- sub') in warnings
+        'circular toctree references detected, ignoring: sub <- index <- sub'
+    ) in warnings
     assert (
-        'circular toctree references detected, ignoring: '
-        'index <- sub <- index') in warnings
+        'circular toctree references detected, ignoring: index <- sub <- index'
+    ) in warnings
 
 
-@pytest.mark.sphinx(buildername='dummy', testroot='images')
+@pytest.mark.sphinx('dummy', testroot='images')
 def test_image_glob(app):
     app.build(force_all=True)
 
@@ -108,16 +117,20 @@ def test_image_glob(app):
     assert doctree[0][2][0]['uri'] == 'rimg.png'
 
     assert isinstance(doctree[0][3], nodes.image)
-    assert doctree[0][3]['candidates'] == {'application/pdf': 'img.pdf',
-                                           'image/gif': 'img.gif',
-                                           'image/png': 'img.png'}
+    assert doctree[0][3]['candidates'] == {
+        'application/pdf': 'img.pdf',
+        'image/gif': 'img.gif',
+        'image/png': 'img.png',
+    }
     assert doctree[0][3]['uri'] == 'img.*'
 
     assert isinstance(doctree[0][4], nodes.figure)
     assert isinstance(doctree[0][4][0], nodes.image)
-    assert doctree[0][4][0]['candidates'] == {'application/pdf': 'img.pdf',
-                                              'image/gif': 'img.gif',
-                                              'image/png': 'img.png'}
+    assert doctree[0][4][0]['candidates'] == {
+        'application/pdf': 'img.pdf',
+        'image/gif': 'img.gif',
+        'image/png': 'img.png',
+    }
     assert doctree[0][4][0]['uri'] == 'img.*'
 
     # subdir/index.rst
@@ -128,14 +141,18 @@ def test_image_glob(app):
     assert doctree[0][1]['uri'] == 'subdir/rimg.png'
 
     assert isinstance(doctree[0][2], nodes.image)
-    assert doctree[0][2]['candidates'] == {'application/pdf': 'subdir/svgimg.pdf',
-                                           'image/svg+xml': 'subdir/svgimg.svg'}
+    assert doctree[0][2]['candidates'] == {
+        'application/pdf': 'subdir/svgimg.pdf',
+        'image/svg+xml': 'subdir/svgimg.svg',
+    }
     assert doctree[0][2]['uri'] == 'subdir/svgimg.*'
 
     assert isinstance(doctree[0][3], nodes.figure)
     assert isinstance(doctree[0][3][0], nodes.image)
-    assert doctree[0][3][0]['candidates'] == {'application/pdf': 'subdir/svgimg.pdf',
-                                              'image/svg+xml': 'subdir/svgimg.svg'}
+    assert doctree[0][3][0]['candidates'] == {
+        'application/pdf': 'subdir/svgimg.pdf',
+        'image/svg+xml': 'subdir/svgimg.svg',
+    }
     assert doctree[0][3][0]['uri'] == 'subdir/svgimg.*'
 
 
diff --git a/tests/test_builders/test_build_changes.py b/tests/test_builders/test_build_changes.py
index 6d070d76855..69db01ba3e5 100644
--- a/tests/test_builders/test_build_changes.py
+++ b/tests/test_builders/test_build_changes.py
@@ -15,18 +15,23 @@ def test_build(app):
 
     path_html = (
         'Path: deprecated: Deprecated since version 0.6:'
-        ' So, that was a bad idea it turns out.')
+        ' So, that was a bad idea it turns out.'
+    )
     assert path_html in htmltext
 
     malloc_html = (
         'void *Test_Malloc(size_t n): changed: Changed in version 0.6:'
-        ' Can now be replaced with a different allocator.')
+        ' Can now be replaced with a different allocator.'
+    )
     assert malloc_html in htmltext
 
 
 @pytest.mark.sphinx(
-    'changes', testroot='changes', srcdir='changes-none',
-    confoverrides={'version': '0.7', 'release': '0.7b1'})
+    'changes',
+    testroot='changes',
+    srcdir='changes-none',
+    confoverrides={'version': '0.7', 'release': '0.7b1'},
+)
 def test_no_changes(app):
     app.build()
 
diff --git a/tests/test_builders/test_build_dirhtml.py b/tests/test_builders/test_build_dirhtml.py
index e80d2a384e5..3e78f1ed0c8 100644
--- a/tests/test_builders/test_build_dirhtml.py
+++ b/tests/test_builders/test_build_dirhtml.py
@@ -7,7 +7,7 @@
 from sphinx.util.inventory import InventoryFile
 
 
-@pytest.mark.sphinx(buildername='dirhtml', testroot='builder-dirhtml')
+@pytest.mark.sphinx('dirhtml', testroot='builder-dirhtml')
 def test_dirhtml(app):
     app.build()
 
@@ -31,10 +31,25 @@ def test_dirhtml(app):
     assert invdata['std:doc']['index'] == ('Project name not set', '', 'path/to/', '-')
 
     assert 'foo/index' in invdata.get('std:doc', {})
-    assert invdata['std:doc']['foo/index'] == ('Project name not set', '', 'path/to/foo/', '-')
+    assert invdata['std:doc']['foo/index'] == (
+        'Project name not set',
+        '',
+        'path/to/foo/',
+        '-',
+    )
 
     assert 'index' in invdata.get('std:label', {})
-    assert invdata['std:label']['index'] == ('Project name not set', '', 'path/to/#index', '-')
+    assert invdata['std:label']['index'] == (
+        'Project name not set',
+        '',
+        'path/to/#index',
+        '-',
+    )
 
     assert 'foo' in invdata.get('std:label', {})
-    assert invdata['std:label']['foo'] == ('Project name not set', '', 'path/to/foo/#foo', 'foo/index')
+    assert invdata['std:label']['foo'] == (
+        'Project name not set',
+        '',
+        'path/to/foo/#foo',
+        'foo/index',
+    )
diff --git a/tests/test_builders/test_build_epub.py b/tests/test_builders/test_build_epub.py
index c0f653c2b48..263fefe8090 100644
--- a/tests/test_builders/test_build_epub.py
+++ b/tests/test_builders/test_build_epub.py
@@ -62,69 +62,87 @@ def __iter__(self):
 @pytest.mark.sphinx('epub', testroot='basic')
 def test_build_epub(app):
     app.build(force_all=True)
-    assert (app.outdir / 'mimetype').read_text(encoding='utf8') == 'application/epub+zip'
+    assert (app.outdir / 'mimetype').read_text(
+        encoding='utf8'
+    ) == 'application/epub+zip'
     assert (app.outdir / 'META-INF' / 'container.xml').exists()
 
     # toc.ncx
-    toc = EPUBElementTree.fromstring((app.outdir / 'toc.ncx').read_text(encoding='utf8'))
-    assert toc.find("./ncx:docTitle/ncx:text").text == 'Project name not set'
+    toc = EPUBElementTree.fromstring(
+        (app.outdir / 'toc.ncx').read_text(encoding='utf8')
+    )
+    assert toc.find('./ncx:docTitle/ncx:text').text == 'Project name not set'
 
     # toc.ncx / head
-    meta = list(toc.find("./ncx:head"))
+    meta = list(toc.find('./ncx:head'))
     assert meta[0].attrib == {'name': 'dtb:uid', 'content': 'unknown'}
     assert meta[1].attrib == {'name': 'dtb:depth', 'content': '1'}
     assert meta[2].attrib == {'name': 'dtb:totalPageCount', 'content': '0'}
     assert meta[3].attrib == {'name': 'dtb:maxPageNumber', 'content': '0'}
 
     # toc.ncx / navMap
-    navpoints = toc.findall("./ncx:navMap/ncx:navPoint")
+    navpoints = toc.findall('./ncx:navMap/ncx:navPoint')
     assert len(navpoints) == 1
     assert navpoints[0].attrib == {'id': 'navPoint1', 'playOrder': '1'}
-    assert navpoints[0].find("./ncx:content").attrib == {'src': 'index.xhtml'}
+    assert navpoints[0].find('./ncx:content').attrib == {'src': 'index.xhtml'}
 
-    navlabel = navpoints[0].find("./ncx:navLabel/ncx:text")
+    navlabel = navpoints[0].find('./ncx:navLabel/ncx:text')
     assert navlabel.text == 'The basic Sphinx documentation for testing'
 
     # content.opf
-    opf = EPUBElementTree.fromstring((app.outdir / 'content.opf').read_text(encoding='utf8'))
+    opf = EPUBElementTree.fromstring(
+        (app.outdir / 'content.opf').read_text(encoding='utf8')
+    )
 
     # content.opf / metadata
-    metadata = opf.find("./idpf:metadata")
-    assert metadata.find("./dc:language").text == 'en'
-    assert metadata.find("./dc:title").text == 'Project name not set'
-    assert metadata.find("./dc:description").text == 'unknown'
-    assert metadata.find("./dc:creator").text == 'Author name not set'
-    assert metadata.find("./dc:contributor").text == 'unknown'
-    assert metadata.find("./dc:publisher").text == 'Author name not set'
-    assert metadata.find("./dc:rights").text is None
+    metadata = opf.find('./idpf:metadata')
+    assert metadata.find('./dc:language').text == 'en'
+    assert metadata.find('./dc:title').text == 'Project name not set'
+    assert metadata.find('./dc:description').text == 'unknown'
+    assert metadata.find('./dc:creator').text == 'Author name not set'
+    assert metadata.find('./dc:contributor').text == 'unknown'
+    assert metadata.find('./dc:publisher').text == 'Author name not set'
+    assert metadata.find('./dc:rights').text is None
     assert metadata.find("./idpf:meta[@property='ibooks:version']").text is None
-    assert metadata.find("./idpf:meta[@property='ibooks:specified-fonts']").text == 'true'
+    assert (
+        metadata.find("./idpf:meta[@property='ibooks:specified-fonts']").text == 'true'
+    )
     assert metadata.find("./idpf:meta[@property='ibooks:binding']").text == 'true'
-    assert metadata.find("./idpf:meta[@property='ibooks:scroll-axis']").text == 'vertical'
+    assert (
+        metadata.find("./idpf:meta[@property='ibooks:scroll-axis']").text == 'vertical'
+    )
 
     # content.opf / manifest
-    manifest = opf.find("./idpf:manifest")
+    manifest = opf.find('./idpf:manifest')
     items = list(manifest)
-    assert items[0].attrib == {'id': 'ncx',
-                               'href': 'toc.ncx',
-                               'media-type': 'application/x-dtbncx+xml'}
-    assert items[1].attrib == {'id': 'nav',
-                               'href': 'nav.xhtml',
-                               'media-type': 'application/xhtml+xml',
-                               'properties': 'nav'}
-    assert items[2].attrib == {'id': 'epub-0',
-                               'href': 'genindex.xhtml',
-                               'media-type': 'application/xhtml+xml'}
-    assert items[3].attrib == {'id': 'epub-1',
-                               'href': 'index.xhtml',
-                               'media-type': 'application/xhtml+xml'}
+    assert items[0].attrib == {
+        'id': 'ncx',
+        'href': 'toc.ncx',
+        'media-type': 'application/x-dtbncx+xml',
+    }
+    assert items[1].attrib == {
+        'id': 'nav',
+        'href': 'nav.xhtml',
+        'media-type': 'application/xhtml+xml',
+        'properties': 'nav',
+    }
+    assert items[2].attrib == {
+        'id': 'epub-0',
+        'href': 'genindex.xhtml',
+        'media-type': 'application/xhtml+xml',
+    }
+    assert items[3].attrib == {
+        'id': 'epub-1',
+        'href': 'index.xhtml',
+        'media-type': 'application/xhtml+xml',
+    }
 
     for i, item in enumerate(items[2:]):
         # items are named as epub-NN
         assert item.get('id') == 'epub-%d' % i
 
     # content.opf / spine
-    spine = opf.find("./idpf:spine")
+    spine = opf.find('./idpf:spine')
     itemrefs = list(spine)
     assert spine.get('toc') == 'ncx'
     assert spine.get('page-progression-direction') == 'ltr'
@@ -132,34 +150,45 @@ def test_build_epub(app):
     assert itemrefs[1].get('idref') == 'epub-0'
 
     # content.opf / guide
-    reference = opf.find("./idpf:guide/idpf:reference")
+    reference = opf.find('./idpf:guide/idpf:reference')
     assert reference.get('type') == 'toc'
     assert reference.get('title') == 'Table of Contents'
     assert reference.get('href') == 'index.xhtml'
 
     # nav.xhtml
-    nav = EPUBElementTree.fromstring((app.outdir / 'nav.xhtml').read_text(encoding='utf8'))
-    assert nav.attrib == {'lang': 'en',
-                          '{http://www.w3.org/XML/1998/namespace}lang': 'en'}
-    assert nav.find("./xhtml:head/xhtml:title").text == 'Table of Contents'
+    nav = EPUBElementTree.fromstring(
+        (app.outdir / 'nav.xhtml').read_text(encoding='utf8')
+    )
+    assert nav.attrib == {
+        'lang': 'en',
+        '{http://www.w3.org/XML/1998/namespace}lang': 'en',
+    }
+    assert nav.find('./xhtml:head/xhtml:title').text == 'Table of Contents'
 
     # nav.xhtml / nav
-    navlist = nav.find("./xhtml:body/xhtml:nav")
-    toc = navlist.findall("./xhtml:ol/xhtml:li")
-    assert navlist.find("./xhtml:h1").text == 'Table of Contents'
+    navlist = nav.find('./xhtml:body/xhtml:nav')
+    toc = navlist.findall('./xhtml:ol/xhtml:li')
+    assert navlist.find('./xhtml:h1').text == 'Table of Contents'
     assert len(toc) == 1
-    assert toc[0].find("./xhtml:a").get("href") == 'index.xhtml'
-    assert toc[0].find("./xhtml:a").text == 'The basic Sphinx documentation for testing'
+    assert toc[0].find('./xhtml:a').get('href') == 'index.xhtml'
+    assert toc[0].find('./xhtml:a').text == 'The basic Sphinx documentation for testing'
 
 
-@pytest.mark.sphinx('epub', testroot='footnotes',
-                    confoverrides={'epub_cover': ('_images/rimg.png', None)})
+@pytest.mark.sphinx(
+    'epub',
+    testroot='footnotes',
+    confoverrides={'epub_cover': ('_images/rimg.png', None)},
+)
 def test_epub_cover(app):
     app.build()
 
     # content.opf / metadata
-    opf = EPUBElementTree.fromstring((app.outdir / 'content.opf').read_text(encoding='utf8'))
-    cover_image = opf.find("./idpf:manifest/idpf:item[@href='%s']" % app.config.epub_cover[0])
+    opf = EPUBElementTree.fromstring(
+        (app.outdir / 'content.opf').read_text(encoding='utf8')
+    )
+    cover_image = opf.find(
+        "./idpf:manifest/idpf:item[@href='%s']" % app.config.epub_cover[0]
+    )
     cover = opf.find("./idpf:metadata/idpf:meta[@name='cover']")
     assert cover
     assert cover.get('content') == cover_image.get('id')
@@ -171,24 +200,27 @@ def test_nested_toc(app):
 
     # toc.ncx
     toc = EPUBElementTree.fromstring((app.outdir / 'toc.ncx').read_bytes())
-    assert toc.find("./ncx:docTitle/ncx:text").text == 'Project name not set'
+    assert toc.find('./ncx:docTitle/ncx:text').text == 'Project name not set'
 
     # toc.ncx / navPoint
     def navinfo(elem: EPUBElementTree):
-        label = elem.find("./ncx:navLabel/ncx:text")
-        content = elem.find("./ncx:content")
-        return (elem.get('id'), elem.get('playOrder'),
-                content.get('src'), label.text)
+        label = elem.find('./ncx:navLabel/ncx:text')
+        content = elem.find('./ncx:content')
+        return elem.get('id'), elem.get('playOrder'), content.get('src'), label.text
 
-    navpoints = toc.findall("./ncx:navMap/ncx:navPoint")
+    navpoints = toc.findall('./ncx:navMap/ncx:navPoint')
     assert len(navpoints) == 4
-    assert navinfo(navpoints[0]) == ('navPoint1', '1', 'index.xhtml',
-                                     "Welcome to Sphinx Tests’s documentation!")
-    assert navpoints[0].findall("./ncx:navPoint") == []
+    assert navinfo(navpoints[0]) == (
+        'navPoint1',
+        '1',
+        'index.xhtml',
+        'Welcome to Sphinx Tests’s documentation!',
+    )
+    assert navpoints[0].findall('./ncx:navPoint') == []
 
     # toc.ncx / nested navPoints
     assert navinfo(navpoints[1]) == ('navPoint2', '2', 'foo.xhtml', 'foo')
-    navchildren = navpoints[1].findall("./ncx:navPoint")
+    navchildren = navpoints[1].findall('./ncx:navPoint')
     assert len(navchildren) == 4
     assert navinfo(navchildren[0]) == ('navPoint3', '2', 'foo.xhtml', 'foo')
     assert navinfo(navchildren[1]) == ('navPoint4', '3', 'quux.xhtml', 'quux')
@@ -197,25 +229,27 @@ def navinfo(elem: EPUBElementTree):
 
     # nav.xhtml / nav
     def navinfo(elem):
-        anchor = elem.find("./xhtml:a")
-        return (anchor.get('href'), anchor.text)
+        anchor = elem.find('./xhtml:a')
+        return anchor.get('href'), anchor.text
 
     nav = EPUBElementTree.fromstring((app.outdir / 'nav.xhtml').read_bytes())
-    toc = nav.findall("./xhtml:body/xhtml:nav/xhtml:ol/xhtml:li")
+    toc = nav.findall('./xhtml:body/xhtml:nav/xhtml:ol/xhtml:li')
     assert len(toc) == 4
-    assert navinfo(toc[0]) == ('index.xhtml',
-                               "Welcome to Sphinx Tests’s documentation!")
-    assert toc[0].findall("./xhtml:ol") == []
+    assert navinfo(toc[0]) == (
+        'index.xhtml',
+        'Welcome to Sphinx Tests’s documentation!',
+    )
+    assert toc[0].findall('./xhtml:ol') == []
 
     # nav.xhtml / nested toc
     assert navinfo(toc[1]) == ('foo.xhtml', 'foo')
-    tocchildren = toc[1].findall("./xhtml:ol/xhtml:li")
+    tocchildren = toc[1].findall('./xhtml:ol/xhtml:li')
     assert len(tocchildren) == 3
     assert navinfo(tocchildren[0]) == ('quux.xhtml', 'quux')
     assert navinfo(tocchildren[1]) == ('foo.xhtml#foo-1', 'foo.1')
     assert navinfo(tocchildren[2]) == ('foo.xhtml#foo-2', 'foo.2')
 
-    grandchild = tocchildren[1].findall("./xhtml:ol/xhtml:li")
+    grandchild = tocchildren[1].findall('./xhtml:ol/xhtml:li')
     assert len(grandchild) == 1
     assert navinfo(grandchild[0]) == ('foo.xhtml#foo-1-1', 'foo.1-1')
 
@@ -226,24 +260,27 @@ def test_escaped_toc(app):
 
     # toc.ncx
     toc = EPUBElementTree.fromstring((app.outdir / 'toc.ncx').read_bytes())
-    assert toc.find("./ncx:docTitle/ncx:text").text == 'need "escaped" project'
+    assert toc.find('./ncx:docTitle/ncx:text').text == 'need "escaped" project'
 
     # toc.ncx / navPoint
     def navinfo(elem):
-        label = elem.find("./ncx:navLabel/ncx:text")
-        content = elem.find("./ncx:content")
-        return (elem.get('id'), elem.get('playOrder'),
-                content.get('src'), label.text)
+        label = elem.find('./ncx:navLabel/ncx:text')
+        content = elem.find('./ncx:content')
+        return elem.get('id'), elem.get('playOrder'), content.get('src'), label.text
 
-    navpoints = toc.findall("./ncx:navMap/ncx:navPoint")
+    navpoints = toc.findall('./ncx:navMap/ncx:navPoint')
     assert len(navpoints) == 4
-    assert navinfo(navpoints[0]) == ('navPoint1', '1', 'index.xhtml',
-                                     "Welcome to Sphinx Tests's documentation!")
-    assert navpoints[0].findall("./ncx:navPoint") == []
+    assert navinfo(navpoints[0]) == (
+        'navPoint1',
+        '1',
+        'index.xhtml',
+        "Welcome to Sphinx Tests's documentation!",
+    )
+    assert navpoints[0].findall('./ncx:navPoint') == []
 
     # toc.ncx / nested navPoints
     assert navinfo(navpoints[1]) == ('navPoint2', '2', 'foo.xhtml', '')
-    navchildren = navpoints[1].findall("./ncx:navPoint")
+    navchildren = navpoints[1].findall('./ncx:navPoint')
     assert len(navchildren) == 4
     assert navinfo(navchildren[0]) == ('navPoint3', '2', 'foo.xhtml', '')
     assert navinfo(navchildren[1]) == ('navPoint4', '3', 'quux.xhtml', 'quux')
@@ -252,25 +289,27 @@ def navinfo(elem):
 
     # nav.xhtml / nav
     def navinfo(elem):
-        anchor = elem.find("./xhtml:a")
-        return (anchor.get('href'), anchor.text)
+        anchor = elem.find('./xhtml:a')
+        return anchor.get('href'), anchor.text
 
     nav = EPUBElementTree.fromstring((app.outdir / 'nav.xhtml').read_bytes())
-    toc = nav.findall("./xhtml:body/xhtml:nav/xhtml:ol/xhtml:li")
+    toc = nav.findall('./xhtml:body/xhtml:nav/xhtml:ol/xhtml:li')
     assert len(toc) == 4
-    assert navinfo(toc[0]) == ('index.xhtml',
-                               "Welcome to Sphinx Tests's documentation!")
-    assert toc[0].findall("./xhtml:ol") == []
+    assert navinfo(toc[0]) == (
+        'index.xhtml',
+        "Welcome to Sphinx Tests's documentation!",
+    )
+    assert toc[0].findall('./xhtml:ol') == []
 
     # nav.xhtml / nested toc
     assert navinfo(toc[1]) == ('foo.xhtml', '')
-    tocchildren = toc[1].findall("./xhtml:ol/xhtml:li")
+    tocchildren = toc[1].findall('./xhtml:ol/xhtml:li')
     assert len(tocchildren) == 3
     assert navinfo(tocchildren[0]) == ('quux.xhtml', 'quux')
     assert navinfo(tocchildren[1]) == ('foo.xhtml#foo-1', 'foo “1”')
     assert navinfo(tocchildren[2]) == ('foo.xhtml#foo-2', 'foo.2')
 
-    grandchild = tocchildren[1].findall("./xhtml:ol/xhtml:li")
+    grandchild = tocchildren[1].findall('./xhtml:ol/xhtml:li')
     assert len(grandchild) == 1
     assert navinfo(grandchild[0]) == ('foo.xhtml#foo-1-1', 'foo.1-1')
 
@@ -281,12 +320,16 @@ def test_epub_writing_mode(app):
     app.build(force_all=True)
 
     # horizontal / page-progression-direction
-    opf = EPUBElementTree.fromstring((app.outdir / 'content.opf').read_text(encoding='utf8'))
-    assert opf.find("./idpf:spine").get('page-progression-direction') == 'ltr'
+    opf = EPUBElementTree.fromstring(
+        (app.outdir / 'content.opf').read_text(encoding='utf8')
+    )
+    assert opf.find('./idpf:spine').get('page-progression-direction') == 'ltr'
 
     # horizontal / ibooks:scroll-axis
-    metadata = opf.find("./idpf:metadata")
-    assert metadata.find("./idpf:meta[@property='ibooks:scroll-axis']").text == 'vertical'
+    metadata = opf.find('./idpf:metadata')
+    assert (
+        metadata.find("./idpf:meta[@property='ibooks:scroll-axis']").text == 'vertical'
+    )
 
     # horizontal / writing-mode (CSS)
     css = (app.outdir / '_static' / 'epub.css').read_text(encoding='utf8')
@@ -298,12 +341,17 @@ def test_epub_writing_mode(app):
     app.build()
 
     # vertical / page-progression-direction
-    opf = EPUBElementTree.fromstring((app.outdir / 'content.opf').read_text(encoding='utf8'))
-    assert opf.find("./idpf:spine").get('page-progression-direction') == 'rtl'
+    opf = EPUBElementTree.fromstring(
+        (app.outdir / 'content.opf').read_text(encoding='utf8')
+    )
+    assert opf.find('./idpf:spine').get('page-progression-direction') == 'rtl'
 
     # vertical / ibooks:scroll-axis
-    metadata = opf.find("./idpf:metadata")
-    assert metadata.find("./idpf:meta[@property='ibooks:scroll-axis']").text == 'horizontal'
+    metadata = opf.find('./idpf:metadata')
+    assert (
+        metadata.find("./idpf:meta[@property='ibooks:scroll-axis']").text
+        == 'horizontal'
+    )
 
     # vertical / writing-mode (CSS)
     css = (app.outdir / '_static' / 'epub.css').read_text(encoding='utf8')
@@ -315,11 +363,13 @@ def test_epub_anchor_id(app):
     app.build()
 
     html = (app.outdir / 'index.xhtml').read_text(encoding='utf8')
-    assert ('

' - 'blah blah blah

' in html) - assert ('' - '

blah blah blah

' in html) - assert 'see ' in html + assert '

blah blah blah

' in html + assert ( + '

blah blah blah

' + ) in html + assert ( + 'see
' + ) in html @pytest.mark.sphinx('epub', testroot='html_assets') @@ -328,26 +378,37 @@ def test_epub_assets(app): # epub_sytlesheets (same as html_css_files) content = (app.outdir / 'index.xhtml').read_text(encoding='utf8') - assert ('' - in content) - assert ('' in content) - - -@pytest.mark.sphinx('epub', testroot='html_assets', - confoverrides={'epub_css_files': ['css/epub.css']}) + assert ( + '' + ) in content + assert ( + '' + ) in content + + +@pytest.mark.sphinx( + 'epub', + testroot='html_assets', + confoverrides={'epub_css_files': ['css/epub.css']}, +) def test_epub_css_files(app): app.build(force_all=True) # epub_css_files content = (app.outdir / 'index.xhtml').read_text(encoding='utf8') - assert '' in content + assert ( + '' + ) in content # files in html_css_files are not outputted - assert ('' - not in content) - assert ('' not in content) + assert ( + '' + ) not in content + assert ( + '' + ) not in content @pytest.mark.sphinx('epub', testroot='roles-download') @@ -356,14 +417,20 @@ def test_html_download_role(app): assert not (app.outdir / '_downloads' / 'dummy.dat').exists() content = (app.outdir / 'index.xhtml').read_text(encoding='utf8') - assert ('
  • ' - 'dummy.dat

  • ' in content) - assert ('
  • ' - 'not_found.dat

  • ' in content) - assert ('
  • ' - 'Sphinx logo' - ' [https://www.sphinx-doc.org/en/master' - '/_static/sphinx-logo.svg]

  • ' in content) + assert ( + '
  • ' + 'dummy.dat

  • ' + ) in content + assert ( + '
  • ' + 'not_found.dat

  • ' + ) in content + assert ( + '
  • ' + 'Sphinx logo' + ' [https://www.sphinx-doc.org/en/master' + '/_static/sphinx-logo.svg]

  • ' + ) in content @pytest.mark.sphinx('epub', testroot='toctree-duplicated') @@ -372,22 +439,27 @@ def test_duplicated_toctree_entry(app): assert 'WARNING: duplicated ToC entry found: foo.xhtml' in app.warning.getvalue() -@pytest.mark.skipif('DO_EPUBCHECK' not in os.environ, - reason='Skipped because DO_EPUBCHECK is not set') +@pytest.mark.skipif( + 'DO_EPUBCHECK' not in os.environ, + reason='Skipped because DO_EPUBCHECK is not set', +) @pytest.mark.sphinx('epub') def test_run_epubcheck(app): app.build() if not runnable(['java', '-version']): - pytest.skip("Unable to run Java; skipping test") + pytest.skip('Unable to run Java; skipping test') epubcheck = os.environ.get('EPUBCHECK_PATH', '/usr/share/java/epubcheck.jar') if not os.path.exists(epubcheck): - pytest.skip("Could not find epubcheck; skipping test") + pytest.skip('Could not find epubcheck; skipping test') try: - subprocess.run(['java', '-jar', epubcheck, app.outdir / 'SphinxTests.epub'], - capture_output=True, check=True) + subprocess.run( + ['java', '-jar', epubcheck, app.outdir / 'SphinxTests.epub'], + capture_output=True, + check=True, + ) except CalledProcessError as exc: print(exc.stdout.decode('utf-8')) print(exc.stderr.decode('utf-8')) diff --git a/tests/test_builders/test_build_gettext.py b/tests/test_builders/test_build_gettext.py index dc8f4c9dcbd..6364b17bae4 100644 --- a/tests/test_builders/test_build_gettext.py +++ b/tests/test_builders/test_build_gettext.py @@ -36,14 +36,19 @@ def test_Catalog_duplicated_message(): msg1, msg2 = list(catalog) assert msg1.text == 'hello' - assert msg1.locations == [('/path/to/filename', 1), - ('/path/to/filename', 2), - ('/path/to/yetanother', 1)] + assert msg1.locations == [ + ('/path/to/filename', 1), + ('/path/to/filename', 2), + ('/path/to/yetanother', 1), + ] assert msg2.text == 'world' assert msg2.locations == [('/path/to/filename', 1)] -@pytest.mark.sphinx('gettext', srcdir='root-gettext') +@pytest.mark.sphinx( + 'gettext', + srcdir='root-gettext', +) def test_build_gettext(app): # Generic build; should fail only when the builder is horribly broken. app.build(force_all=True) @@ -59,14 +64,24 @@ def test_build_gettext(app): assert 'msgid "something, something else, something more"' in catalog -@pytest.mark.sphinx('gettext', srcdir='root-gettext') +@pytest.mark.sphinx( + 'gettext', + srcdir='root-gettext', +) def test_msgfmt(app): app.build(force_all=True) (app.outdir / 'en' / 'LC_MESSAGES').mkdir(parents=True, exist_ok=True) with chdir(app.outdir): try: - args = ['msginit', '--no-translator', '-i', 'markup.pot', '--locale', 'en_US'] + args = [ + 'msginit', + '--no-translator', + '-i', + 'markup.pot', + '--locale', + 'en_US', + ] subprocess.run(args, capture_output=True, check=True) except OSError: pytest.skip() # most likely msginit was not found @@ -78,8 +93,12 @@ def test_msgfmt(app): assert (app.outdir / 'en_US.po').is_file(), 'msginit failed' try: - args = ['msgfmt', 'en_US.po', - '-o', os.path.join('en', 'LC_MESSAGES', 'test_root.mo')] + args = [ + 'msgfmt', + 'en_US.po', + '-o', + os.path.join('en', 'LC_MESSAGES', 'test_root.mo'), + ] subprocess.run(args, capture_output=True, check=True) except OSError: pytest.skip() # most likely msgfmt was not found @@ -93,12 +112,15 @@ def test_msgfmt(app): assert mo.is_file(), 'msgfmt failed' _ = gettext.translation('test_root', app.outdir, languages=['en']).gettext - assert _("Testing various markup") == "Testing various markup" + assert _('Testing various markup') == 'Testing various markup' @pytest.mark.sphinx( - 'gettext', testroot='intl', srcdir='gettext', - confoverrides={'gettext_compact': False}) + 'gettext', + testroot='intl', + srcdir='gettext', + confoverrides={'gettext_compact': False}, +) def test_gettext_index_entries(app): # regression test for #976 app.build(filenames=[app.srcdir / 'index_entries.txt']) @@ -107,26 +129,28 @@ def test_gettext_index_entries(app): msg_ids = get_msgids(pot) assert msg_ids == [ - "i18n with index entries", - "index target section", - "this is :index:`Newsletter` target paragraph.", - "various index entries", + 'i18n with index entries', + 'index target section', + 'this is :index:`Newsletter` target paragraph.', + 'various index entries', "That's all.", - "Mailing List", - "Newsletter", - "Recipients List", - "First", - "Second", - "Third", - "Entry", - "See", + 'Mailing List', + 'Newsletter', + 'Recipients List', + 'First', + 'Second', + 'Third', + 'Entry', + 'See', ] @pytest.mark.sphinx( - 'gettext', testroot='intl', srcdir='gettext', - confoverrides={'gettext_compact': False, - 'gettext_additional_targets': []}) + 'gettext', + testroot='intl', + srcdir='gettext', + confoverrides={'gettext_compact': False, 'gettext_additional_targets': []}, +) def test_gettext_disable_index_entries(app): # regression test for #976 app.env._pickled_doctree_cache.clear() # clear cache @@ -136,23 +160,27 @@ def test_gettext_disable_index_entries(app): msg_ids = get_msgids(pot) assert msg_ids == [ - "i18n with index entries", - "index target section", - "this is :index:`Newsletter` target paragraph.", - "various index entries", + 'i18n with index entries', + 'index target section', + 'this is :index:`Newsletter` target paragraph.', + 'various index entries', "That's all.", ] -@pytest.mark.sphinx('gettext', testroot='intl', srcdir='gettext') +@pytest.mark.sphinx( + 'gettext', + testroot='intl', + srcdir='gettext', +) def test_gettext_template(app): app.build(force_all=True) assert (app.outdir / 'sphinx.pot').is_file() result = (app.outdir / 'sphinx.pot').read_text(encoding='utf8') - assert "Welcome" in result - assert "Sphinx %(version)s" in result + assert 'Welcome' in result + assert 'Sphinx %(version)s' in result @pytest.mark.sphinx('gettext', testroot='gettext-template') @@ -162,17 +190,22 @@ def test_gettext_template_msgid_order_in_sphinxpot(app): result = (app.outdir / 'sphinx.pot').read_text(encoding='utf8') assert re.search( - ('msgid "Template 1".*' - 'msgid "This is Template 1\\.".*' - 'msgid "Template 2".*' - 'msgid "This is Template 2\\.".*'), + ( + 'msgid "Template 1".*' + 'msgid "This is Template 1\\.".*' + 'msgid "Template 2".*' + 'msgid "This is Template 2\\.".*' + ), result, - flags=re.DOTALL) + flags=re.DOTALL, + ) @pytest.mark.sphinx( - 'gettext', srcdir='root-gettext', - confoverrides={'gettext_compact': 'documentation'}) + 'gettext', + srcdir='root-gettext', + confoverrides={'gettext_compact': 'documentation'}, +) def test_build_single_pot(app): app.build(force_all=True) @@ -180,20 +213,23 @@ def test_build_single_pot(app): result = (app.outdir / 'documentation.pot').read_text(encoding='utf8') assert re.search( - ('msgid "Todo".*' - 'msgid "Like footnotes.".*' - 'msgid "The minute.".*' - 'msgid "Generated section".*'), + ( + 'msgid "Todo".*' + 'msgid "Like footnotes.".*' + 'msgid "The minute.".*' + 'msgid "Generated section".*' + ), result, - flags=re.DOTALL) + flags=re.DOTALL, + ) @pytest.mark.sphinx( 'gettext', testroot='intl_substitution_definitions', srcdir='gettext-subst', - confoverrides={'gettext_compact': False, - 'gettext_additional_targets': ['image']}) + confoverrides={'gettext_compact': False, 'gettext_additional_targets': ['image']}, +) def test_gettext_prolog_epilog_substitution(app): app.build(force_all=True) @@ -202,15 +238,15 @@ def test_gettext_prolog_epilog_substitution(app): msg_ids = get_msgids(pot) assert msg_ids == [ - "i18n with prologue and epilogue substitutions", - "This is content that contains |subst_prolog_1|.", - "Substituted image |subst_prolog_2| here.", - "subst_prolog_2", - ".. image:: /img.png", - "This is content that contains |subst_epilog_1|.", - "Substituted image |subst_epilog_2| here.", - "subst_epilog_2", - ".. image:: /i18n.png", + 'i18n with prologue and epilogue substitutions', + 'This is content that contains |subst_prolog_1|.', + 'Substituted image |subst_prolog_2| here.', + 'subst_prolog_2', + '.. image:: /img.png', + 'This is content that contains |subst_epilog_1|.', + 'Substituted image |subst_epilog_2| here.', + 'subst_epilog_2', + '.. image:: /i18n.png', ] @@ -218,26 +254,32 @@ def test_gettext_prolog_epilog_substitution(app): 'gettext', testroot='intl_substitution_definitions', srcdir='gettext-subst', - confoverrides={'gettext_compact': False, - 'gettext_additional_targets': ['image']}) + confoverrides={'gettext_compact': False, 'gettext_additional_targets': ['image']}, +) def test_gettext_prolog_epilog_substitution_excluded(app): # regression test for #9428 app.build(force_all=True) assert (app.outdir / 'prolog_epilog_substitution_excluded.pot').is_file() - pot = (app.outdir / 'prolog_epilog_substitution_excluded.pot').read_text(encoding='utf8') + pot = (app.outdir / 'prolog_epilog_substitution_excluded.pot').read_text( + encoding='utf8' + ) msg_ids = get_msgids(pot) assert msg_ids == [ - "i18n without prologue and epilogue substitutions", - "This is content that does not include prologue and epilogue substitutions.", + 'i18n without prologue and epilogue substitutions', + 'This is content that does not include prologue and epilogue substitutions.', ] @pytest.mark.sphinx( - 'gettext', srcdir='gettext', - confoverrides={'gettext_compact': False, - 'gettext_additional_targets': ['literal-block', 'doctest-block']}) + 'gettext', + srcdir='gettext', + confoverrides={ + 'gettext_compact': False, + 'gettext_additional_targets': ['literal-block', 'doctest-block'], + }, +) def test_gettext_literalblock_additional(app): app.build(force_all=True) diff --git a/tests/test_builders/test_build_html.py b/tests/test_builders/test_build_html.py index 847565e8e48..93e770cca9c 100644 --- a/tests/test_builders/test_build_html.py +++ b/tests/test_builders/test_build_html.py @@ -27,49 +27,103 @@ def test_html_sidebars_error(make_app, tmp_path): with pytest.raises( ConfigError, match="Values in 'html_sidebars' must be a list of strings. " - "At least one pattern has a string value: 'index'. " - r"Change to `html_sidebars = \{'index': \['searchbox.html'\]\}`.", + "At least one pattern has a string value: 'index'. " + r"Change to `html_sidebars = \{'index': \['searchbox.html'\]\}`.", ): make_app( - buildername='html', + 'html', srcdir=tmp_path, confoverrides={'html_sidebars': {'index': 'searchbox.html'}}, ) def test_html4_error(make_app, tmp_path): - (tmp_path / 'conf.py').write_text('', encoding='utf-8') + (tmp_path / 'conf.py').touch() with pytest.raises( ConfigError, match='HTML 4 is no longer supported by Sphinx', ): make_app( - buildername='html', + 'html', srcdir=tmp_path, confoverrides={'html4_writer': True}, ) -@pytest.mark.parametrize(("fname", "path", "check"), [ - ('index.html', ".//div[@class='citation']/span", r'Ref1'), - ('index.html', ".//div[@class='citation']/span", r'Ref_1'), - - ('footnote.html', ".//a[@class='footnote-reference brackets'][@href='#id9'][@id='id1']", r"1"), - ('footnote.html', ".//a[@class='footnote-reference brackets'][@href='#id10'][@id='id2']", r"2"), - ('footnote.html', ".//a[@class='footnote-reference brackets'][@href='#foo'][@id='id3']", r"3"), - ('footnote.html', ".//a[@class='reference internal'][@href='#bar'][@id='id4']/span", r"\[bar\]"), - ('footnote.html', ".//a[@class='reference internal'][@href='#baz-qux'][@id='id5']/span", r"\[baz_qux\]"), - ('footnote.html', ".//a[@class='footnote-reference brackets'][@href='#id11'][@id='id6']", r"4"), - ('footnote.html', ".//a[@class='footnote-reference brackets'][@href='#id12'][@id='id7']", r"5"), - ('footnote.html', ".//aside[@class='footnote brackets']/span/a[@href='#id1']", r"1"), - ('footnote.html', ".//aside[@class='footnote brackets']/span/a[@href='#id2']", r"2"), - ('footnote.html', ".//aside[@class='footnote brackets']/span/a[@href='#id3']", r"3"), - ('footnote.html', ".//div[@class='citation']/span/a[@href='#id4']", r"bar"), - ('footnote.html', ".//div[@class='citation']/span/a[@href='#id5']", r"baz_qux"), - ('footnote.html', ".//aside[@class='footnote brackets']/span/a[@href='#id6']", r"4"), - ('footnote.html', ".//aside[@class='footnote brackets']/span/a[@href='#id7']", r"5"), - ('footnote.html', ".//aside[@class='footnote brackets']/span/a[@href='#id8']", r"6"), -]) +@pytest.mark.parametrize( + ('fname', 'path', 'check'), + [ + ('index.html', ".//div[@class='citation']/span", r'Ref1'), + ('index.html', ".//div[@class='citation']/span", r'Ref_1'), + ( + 'footnote.html', + ".//a[@class='footnote-reference brackets'][@href='#id9'][@id='id1']", + r'1', + ), + ( + 'footnote.html', + ".//a[@class='footnote-reference brackets'][@href='#id10'][@id='id2']", + r'2', + ), + ( + 'footnote.html', + ".//a[@class='footnote-reference brackets'][@href='#foo'][@id='id3']", + r'3', + ), + ( + 'footnote.html', + ".//a[@class='reference internal'][@href='#bar'][@id='id4']/span", + r'\[bar\]', + ), + ( + 'footnote.html', + ".//a[@class='reference internal'][@href='#baz-qux'][@id='id5']/span", + r'\[baz_qux\]', + ), + ( + 'footnote.html', + ".//a[@class='footnote-reference brackets'][@href='#id11'][@id='id6']", + r'4', + ), + ( + 'footnote.html', + ".//a[@class='footnote-reference brackets'][@href='#id12'][@id='id7']", + r'5', + ), + ( + 'footnote.html', + ".//aside[@class='footnote brackets']/span/a[@href='#id1']", + r'1', + ), + ( + 'footnote.html', + ".//aside[@class='footnote brackets']/span/a[@href='#id2']", + r'2', + ), + ( + 'footnote.html', + ".//aside[@class='footnote brackets']/span/a[@href='#id3']", + r'3', + ), + ('footnote.html', ".//div[@class='citation']/span/a[@href='#id4']", r'bar'), + ('footnote.html', ".//div[@class='citation']/span/a[@href='#id5']", r'baz_qux'), + ( + 'footnote.html', + ".//aside[@class='footnote brackets']/span/a[@href='#id6']", + r'4', + ), + ( + 'footnote.html', + ".//aside[@class='footnote brackets']/span/a[@href='#id7']", + r'5', + ), + ( + 'footnote.html', + ".//aside[@class='footnote brackets']/span/a[@href='#id8']", + r'6', + ), + ], +) @pytest.mark.sphinx('html') @pytest.mark.test_params(shared_result='test_build_html_output_docutils18') def test_docutils_output(app, cached_etree_parse, fname, path, check): @@ -77,7 +131,10 @@ def test_docutils_output(app, cached_etree_parse, fname, path, check): check_xpath(cached_etree_parse(app.outdir / fname), fname, path, check) -@pytest.mark.sphinx('html', parallel=2) +@pytest.mark.sphinx( + 'html', + parallel=2, +) def test_html_parallel(app): app.build() @@ -88,44 +145,66 @@ def test_html_translator(app): assert app.builder.docwriter.visitor.depart_with_node == 10 -@pytest.mark.parametrize("expect", [ - (FIGURE_CAPTION + "//span[@class='caption-number']", "Fig. 1", True), - (FIGURE_CAPTION + "//span[@class='caption-number']", "Fig. 2", True), - (FIGURE_CAPTION + "//span[@class='caption-number']", "Fig. 3", True), - (".//div//span[@class='caption-number']", "No.1 ", True), - (".//div//span[@class='caption-number']", "No.2 ", True), - (".//li/p/a/span", 'Fig. 1', True), - (".//li/p/a/span", 'Fig. 2', True), - (".//li/p/a/span", 'Fig. 3', True), - (".//li/p/a/span", 'No.1', True), - (".//li/p/a/span", 'No.2', True), -]) -@pytest.mark.sphinx('html', testroot='add_enumerable_node', - srcdir='test_enumerable_node') +@pytest.mark.parametrize( + 'expect', + [ + (FIGURE_CAPTION + "//span[@class='caption-number']", 'Fig. 1', True), + (FIGURE_CAPTION + "//span[@class='caption-number']", 'Fig. 2', True), + (FIGURE_CAPTION + "//span[@class='caption-number']", 'Fig. 3', True), + (".//div//span[@class='caption-number']", 'No.1 ', True), + (".//div//span[@class='caption-number']", 'No.2 ', True), + ('.//li/p/a/span', 'Fig. 1', True), + ('.//li/p/a/span', 'Fig. 2', True), + ('.//li/p/a/span', 'Fig. 3', True), + ('.//li/p/a/span', 'No.1', True), + ('.//li/p/a/span', 'No.2', True), + ], +) +@pytest.mark.sphinx( + 'html', + testroot='add_enumerable_node', + srcdir='test_enumerable_node', +) def test_enumerable_node(app, cached_etree_parse, expect): app.build() check_xpath(cached_etree_parse(app.outdir / 'index.html'), 'index.html', *expect) -@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_copy_source': False}) +@pytest.mark.sphinx( + 'html', + testroot='basic', + confoverrides={'html_copy_source': False}, +) def test_html_copy_source(app): app.build(force_all=True) assert not (app.outdir / '_sources' / 'index.rst.txt').exists() -@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': '.txt'}) +@pytest.mark.sphinx( + 'html', + testroot='basic', + confoverrides={'html_sourcelink_suffix': '.txt'}, +) def test_html_sourcelink_suffix(app): app.build(force_all=True) assert (app.outdir / '_sources' / 'index.rst.txt').exists() -@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': '.rst'}) +@pytest.mark.sphinx( + 'html', + testroot='basic', + confoverrides={'html_sourcelink_suffix': '.rst'}, +) def test_html_sourcelink_suffix_same(app): app.build(force_all=True) assert (app.outdir / '_sources' / 'index.rst').exists() -@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': ''}) +@pytest.mark.sphinx( + 'html', + testroot='basic', + confoverrides={'html_sourcelink_suffix': ''}, +) def test_html_sourcelink_suffix_empty(app): app.build(force_all=True) assert (app.outdir / '_sources' / 'index.rst').exists() @@ -148,40 +227,57 @@ def test_html_inventory(app): invdata = InventoryFile.load(f, 'https://www.google.com', posixpath.join) assert set(invdata.keys()) == {'std:label', 'std:doc'} - assert set(invdata['std:label'].keys()) == {'modindex', - 'py-modindex', - 'genindex', - 'search'} - assert invdata['std:label']['modindex'] == ('Project name not set', - '', - 'https://www.google.com/py-modindex.html', - 'Module Index') - assert invdata['std:label']['py-modindex'] == ('Project name not set', - '', - 'https://www.google.com/py-modindex.html', - 'Python Module Index') - assert invdata['std:label']['genindex'] == ('Project name not set', - '', - 'https://www.google.com/genindex.html', - 'Index') - assert invdata['std:label']['search'] == ('Project name not set', - '', - 'https://www.google.com/search.html', - 'Search Page') + assert set(invdata['std:label'].keys()) == { + 'modindex', + 'py-modindex', + 'genindex', + 'search', + } + assert invdata['std:label']['modindex'] == ( + 'Project name not set', + '', + 'https://www.google.com/py-modindex.html', + 'Module Index', + ) + assert invdata['std:label']['py-modindex'] == ( + 'Project name not set', + '', + 'https://www.google.com/py-modindex.html', + 'Python Module Index', + ) + assert invdata['std:label']['genindex'] == ( + 'Project name not set', + '', + 'https://www.google.com/genindex.html', + 'Index', + ) + assert invdata['std:label']['search'] == ( + 'Project name not set', + '', + 'https://www.google.com/search.html', + 'Search Page', + ) assert set(invdata['std:doc'].keys()) == {'index'} - assert invdata['std:doc']['index'] == ('Project name not set', - '', - 'https://www.google.com/index.html', - 'The basic Sphinx documentation for testing') + assert invdata['std:doc']['index'] == ( + 'Project name not set', + '', + 'https://www.google.com/index.html', + 'The basic Sphinx documentation for testing', + ) -@pytest.mark.sphinx('html', testroot='images', confoverrides={'html_sourcelink_suffix': ''}) +@pytest.mark.sphinx( + 'html', + testroot='images', + confoverrides={'html_sourcelink_suffix': ''}, +) def test_html_anchor_for_figure(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') - assert ('
    \n

    The caption of pic' - '

    \n
    ' - in content) + assert ( + '
    \n

    The caption of pic' + '

    \n
    ' + ) in content @pytest.mark.sphinx('html', testroot='directives-raw') @@ -198,28 +294,56 @@ def test_html_raw_directive(app): assert '

    LaTeX: abc ghi

    ' in result -@pytest.mark.parametrize("expect", [ - (".//link[@href='_static/persistent.css']" - "[@rel='stylesheet']", '', True), - (".//link[@href='_static/default.css']" - "[@rel='stylesheet']" - "[@title='Default']", '', True), - (".//link[@href='_static/alternate1.css']" - "[@rel='alternate stylesheet']" - "[@title='Alternate']", '', True), - (".//link[@href='_static/alternate2.css']" - "[@rel='alternate stylesheet']", '', True), - (".//link[@href='_static/more_persistent.css']" - "[@rel='stylesheet']", '', True), - (".//link[@href='_static/more_default.css']" - "[@rel='stylesheet']" - "[@title='Default']", '', True), - (".//link[@href='_static/more_alternate1.css']" - "[@rel='alternate stylesheet']" - "[@title='Alternate']", '', True), - (".//link[@href='_static/more_alternate2.css']" - "[@rel='alternate stylesheet']", '', True), -]) +@pytest.mark.parametrize( + 'expect', + [ + (".//link[@href='_static/persistent.css'][@rel='stylesheet']", '', True), + ( + ".//link[@href='_static/default.css']" + "[@rel='stylesheet']" + "[@title='Default']", + '', + True, + ), + ( + ".//link[@href='_static/alternate1.css']" + "[@rel='alternate stylesheet']" + "[@title='Alternate']", + '', + True, + ), + ( + ".//link[@href='_static/alternate2.css'][@rel='alternate stylesheet']", + '', + True, + ), + ( + ".//link[@href='_static/more_persistent.css'][@rel='stylesheet']", + '', + True, + ), + ( + ".//link[@href='_static/more_default.css']" + "[@rel='stylesheet']" + "[@title='Default']", + '', + True, + ), + ( + ".//link[@href='_static/more_alternate1.css']" + "[@rel='alternate stylesheet']" + "[@title='Alternate']", + '', + True, + ), + ( + ".//link[@href='_static/more_alternate2.css']" + "[@rel='alternate stylesheet']", + '', + True, + ), + ], +) @pytest.mark.sphinx('html', testroot='stylesheets') def test_alternate_stylesheets(app, cached_etree_parse, expect): app.build() @@ -230,22 +354,29 @@ def test_alternate_stylesheets(app, cached_etree_parse, expect): def test_html_style(app): app.build() result = (app.outdir / 'index.html').read_text(encoding='utf8') - assert '' in result - assert ('' - not in result) + assert ( + '' + ) in result + assert ( + '' + ) not in result @pytest.mark.sphinx( 'html', testroot='basic', # alabaster changed default sidebars in 1.0.0 - confoverrides={'html_sidebars': {'**': [ - 'about.html', - 'navigation.html', - 'relations.html', - 'searchbox.html', - 'donate.html', - ]}}, + confoverrides={ + 'html_sidebars': { + '**': [ + 'about.html', + 'navigation.html', + 'relations.html', + 'searchbox.html', + 'donate.html', + ] + } + }, ) def test_html_sidebar(app): ctx: dict[str, Any] = {} @@ -253,23 +384,26 @@ def test_html_sidebar(app): # default for alabaster app.build(force_all=True) result = (app.outdir / 'index.html').read_text(encoding='utf8') - assert ('