From 0a6db489e08ce9bf955638aac49155b1d4001566 Mon Sep 17 00:00:00 2001 From: eugenioseveri Date: Thu, 31 Oct 2024 12:45:55 +0100 Subject: [PATCH 01/15] Updated python linters also in '_python.yml' workflow --- .github/workflows/_python.yml | 12 ++++++------ workflows/_python.yml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index d24cd1b..ac68e9a 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -310,32 +310,32 @@ jobs: echo > requirements-linters.txt if [[ '${{ inputs.use_black}}' != 'false' ]]; then - echo "black==23.11.0" >> requirements-linters.txt + echo "black==24.8.0" >> requirements-linters.txt fi if [[ '${{ inputs.use_isort}}' != 'false' ]]; then - echo "isort==5.12.0" >> requirements-linters.txt + echo "isort==5.13.2" >> requirements-linters.txt fi if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then - echo "flake8==6.1.0" >> requirements-linters.txt + echo "flake8==7.1.1" >> requirements-linters.txt if [[ -n '${{ inputs.django_settings_module }}' ]]; then echo "flake8-django==1.4" >> requirements-linters.txt fi fi if [[ '${{ inputs.use_pylint}}' != 'false' ]]; then - echo "pylint==2.17.7" >> requirements-linters.txt + echo "pylint==3.2.6" >> requirements-linters.txt if [[ -n '${{ inputs.django_settings_module }}' ]]; then echo "pylint-django==2.5.5" >> requirements-linters.txt fi fi if [[ '${{ inputs.use_bandit}}' != 'false' ]]; then - echo "bandit==1.7.5" >> requirements-linters.txt + echo "bandit==1.7.9" >> requirements-linters.txt fi if [[ '${{ inputs.use_autoflake}}' != 'false' ]]; then - echo "autoflake==2.2.1" >> requirements-linters.txt + echo "autoflake==2.3.1" >> requirements-linters.txt fi cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-linter.txt/') >> requirements-linters.txt 2>/dev/null || exit 0 shell: bash diff --git a/workflows/_python.yml b/workflows/_python.yml index d24cd1b..ac68e9a 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -310,32 +310,32 @@ jobs: echo > requirements-linters.txt if [[ '${{ inputs.use_black}}' != 'false' ]]; then - echo "black==23.11.0" >> requirements-linters.txt + echo "black==24.8.0" >> requirements-linters.txt fi if [[ '${{ inputs.use_isort}}' != 'false' ]]; then - echo "isort==5.12.0" >> requirements-linters.txt + echo "isort==5.13.2" >> requirements-linters.txt fi if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then - echo "flake8==6.1.0" >> requirements-linters.txt + echo "flake8==7.1.1" >> requirements-linters.txt if [[ -n '${{ inputs.django_settings_module }}' ]]; then echo "flake8-django==1.4" >> requirements-linters.txt fi fi if [[ '${{ inputs.use_pylint}}' != 'false' ]]; then - echo "pylint==2.17.7" >> requirements-linters.txt + echo "pylint==3.2.6" >> requirements-linters.txt if [[ -n '${{ inputs.django_settings_module }}' ]]; then echo "pylint-django==2.5.5" >> requirements-linters.txt fi fi if [[ '${{ inputs.use_bandit}}' != 'false' ]]; then - echo "bandit==1.7.5" >> requirements-linters.txt + echo "bandit==1.7.9" >> requirements-linters.txt fi if [[ '${{ inputs.use_autoflake}}' != 'false' ]]; then - echo "autoflake==2.2.1" >> requirements-linters.txt + echo "autoflake==2.3.1" >> requirements-linters.txt fi cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-linter.txt/') >> requirements-linters.txt 2>/dev/null || exit 0 shell: bash From a492676b12c089f1c73cc32d6a95d7a9d2f481a5 Mon Sep 17 00:00:00 2001 From: Alberto Cocheo <88388252+acocheo@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:13:59 +0100 Subject: [PATCH 02/15] Deprecation of license check `table-headers` (#212) * Deprecation of license check `table-headers` * Fix * Try fix node test --- .github/test/node_test/package-lock.json | 4337 +++++++++++++++------- .github/test/node_test/package.json | 14 +- .github/workflows/_node.yml | 4 +- .github/workflows/_python.yml | 4 +- workflows/_node.yml | 4 +- workflows/_python.yml | 4 +- 6 files changed, 3006 insertions(+), 1361 deletions(-) diff --git a/.github/test/node_test/package-lock.json b/.github/test/node_test/package-lock.json index 8e9d393..3f101d9 100644 --- a/.github/test/node_test/package-lock.json +++ b/.github/test/node_test/package-lock.json @@ -8,496 +8,1491 @@ "name": "node_test", "version": "1.0.0", "dependencies": { - "react": "^18.2.0" + "react": "^19.0.0", + "react-dom": "^19.0.0" }, "devDependencies": { + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.1.0", + "babel-jest": "^29.7.0", "eslint": "^8.20.0", - "husky": "^8.0.1", - "jest": "^29.1.1", + "husky": "^9.1.7", + "jest": "^29.7.0", "lint-staged": "^15.1.0", "prettier": "^3.1.0", - "stylelint": "^15.2.0" + "stylelint": "^16.12.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.1.tgz", + "integrity": "sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", + "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", - "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { - "node": ">=0.8.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/@babel/compat-data": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", - "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/core": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", - "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, + "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.3", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/generator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", - "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", + "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helpers": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", - "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.4", - "@babel/types": "^7.23.4" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" + }, "engines": { - "node": ">=0.8.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", - "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -506,100 +1501,197 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "node_modules/@babel/preset-env": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -608,35 +1700,62 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", - "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.4", - "@babel/generator": "^7.23.4", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.4", - "@babel/types": "^7.23.4", - "debug": "^4.1.0", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.3", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -648,19 +1767,20 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@babel/types": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", - "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -670,12 +1790,13 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.2.tgz", - "integrity": "sha512-sLYGdAdEY2x7TSw9FtmdaTrh2wFtRJO5VMbBrA8tEqEod7GEggFmxTSK9XqExib3yMuYNcvcTdCZIP6ukdjAIA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", "dev": true, "funding": [ { @@ -687,17 +1808,18 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.2.1" + "@csstools/css-tokenizer": "^3.0.3" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.1.tgz", - "integrity": "sha512-Zmsf2f/CaEPWEVgw29odOj+WEVoiJy9s9NOv5GgNY9mZ1CZ7394By6wONrONrTsnNDv6F9hR02nvFihrGVGHBg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", "dev": true, "funding": [ { @@ -709,14 +1831,15 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=18" } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.5.tgz", - "integrity": "sha512-IxVBdYzR8pYe89JiyXQuYk4aVVoCPhMJkz6ElRwlVysjwURTsTk/bmY/z4FfeRE+CRBMlykPwXEVUg8lThv7AQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", "dev": true, "funding": [ { @@ -728,18 +1851,19 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.3.2", - "@csstools/css-tokenizer": "^2.2.1" + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz", - "integrity": "sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", "dev": true, "funding": [ { @@ -751,42 +1875,60 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT-0", "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=18" }, "peerDependencies": { - "postcss-selector-parser": "^6.0.13" + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@dual-bundle/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -806,22 +1948,25 @@ } }, "node_modules/@eslint/js": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -833,6 +1978,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -842,16 +1988,19 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -868,6 +2017,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -877,6 +2027,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -890,6 +2041,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -903,6 +2055,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -915,6 +2068,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -930,6 +2084,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -942,6 +2097,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -951,6 +2107,7 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -960,6 +2117,7 @@ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -977,6 +2135,7 @@ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", @@ -1024,6 +2183,7 @@ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -1039,6 +2199,7 @@ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -1052,6 +2213,7 @@ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -1064,6 +2226,7 @@ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -1081,6 +2244,7 @@ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -1096,6 +2260,7 @@ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", @@ -1139,6 +2304,7 @@ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -1151,6 +2317,7 @@ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", "callsites": "^3.0.0", @@ -1165,6 +2332,7 @@ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", @@ -1180,6 +2348,7 @@ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", @@ -1195,6 +2364,7 @@ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -1221,6 +2391,7 @@ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -1234,48 +2405,53 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1286,6 +2462,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1299,6 +2476,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1308,6 +2486,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1320,13 +2499,15 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } @@ -1336,15 +2517,203 @@ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", + "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.1.0.tgz", + "integrity": "sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/babel__core": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", - "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1354,10 +2723,11 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", - "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -1367,16 +2737,18 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", - "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } @@ -1386,6 +2758,7 @@ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1394,13 +2767,15 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -1410,42 +2785,34 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", - "dev": true - }, "node_modules/@types/node": { - "version": "20.9.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz", - "integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==", + "version": "22.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.3.tgz", + "integrity": "sha512-DifAyw4BkrufCILvD3ucnuN8eydUfc/C1GlyrnI+LK6543w5/L3VeVgf05o3B4fqSXP1dKYLOZsKfutpxPzZrw==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.20.0" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true - }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yargs": { - "version": "17.0.31", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", - "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -1454,19 +2821,22 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "dev": true, + "license": "ISC" }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1479,6 +2849,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1488,6 +2859,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1504,6 +2876,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -1519,6 +2892,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1531,6 +2905,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1540,6 +2915,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1555,6 +2931,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1567,31 +2944,35 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1601,6 +2982,7 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -1622,6 +3004,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -1638,6 +3021,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -1654,6 +3038,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -1664,24 +3049,70 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", + "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.3", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", + "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0" @@ -1692,6 +3123,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, + "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -1707,34 +3139,37 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "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==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", "dev": true, "funding": [ { @@ -1750,11 +3185,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -1768,6 +3204,7 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } @@ -1776,13 +3213,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1792,56 +3231,15 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/camelcase-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", - "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", - "dev": true, - "dependencies": { - "camelcase": "^6.3.0", - "map-obj": "^4.1.0", - "quick-lru": "^5.1.1", - "type-fest": "^1.2.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-keys/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/caniuse-lite": { - "version": "1.0.30001563", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz", - "integrity": "sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw==", + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", "dev": true, "funding": [ { @@ -1856,13 +3254,15 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1879,6 +3279,7 @@ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -1894,42 +3295,46 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "dev": true, + "license": "MIT" }, "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, + "license": "MIT", "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, + "license": "MIT", "dependencies": { "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" + "string-width": "^7.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1940,6 +3345,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1953,13 +3359,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1969,6 +3377,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1983,6 +3392,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2000,6 +3410,7 @@ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -2009,13 +3420,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2027,51 +3440,72 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } }, "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, + "license": "MIT", "dependencies": { + "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" @@ -2093,6 +3527,7 @@ "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -2110,10 +3545,11 @@ } }, "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==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2124,32 +3560,42 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.1.tgz", - "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", + "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12 || >=16" } }, "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, + "license": "MIT", "dependencies": { - "mdn-data": "2.0.30", + "mdn-data": "2.12.2", "source-map-js": "^1.0.1" }, "engines": { "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -2158,12 +3604,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2174,57 +3621,12 @@ } } }, - "node_modules/decamelize": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", - "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, + "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -2238,22 +3640,36 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2263,6 +3679,7 @@ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -2272,6 +3689,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -2284,6 +3702,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -2291,23 +3710,26 @@ "node": ">=6.0.0" } }, - "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-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.588", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.588.tgz", - "integrity": "sha512-soytjxwbgcCu7nh5Pf4S2/4wa6UIu+A3p03U2yVr53qGxi1/VTR3ENI+p50v+UxqqZAfl48j3z55ud7VHIOr9w==", - "dev": true + "version": "1.5.76", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", + "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", + "dev": true, + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -2316,25 +3738,51 @@ } }, "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 + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2344,6 +3792,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2352,16 +3801,18 @@ } }, "node_modules/eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -2411,6 +3862,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -2427,6 +3879,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2439,6 +3892,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -2456,6 +3910,7 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -2465,10 +3920,11 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -2481,6 +3937,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -2493,6 +3950,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -2502,6 +3960,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -2510,13 +3969,15 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -2549,6 +4010,7 @@ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -2564,13 +4026,15 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -2587,6 +4051,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -2598,28 +4063,39 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.9.1" } }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -2629,6 +4105,7 @@ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -2638,6 +4115,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -2646,10 +4124,11 @@ } }, "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==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2662,6 +4141,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -2678,6 +4158,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -2688,16 +4169,18 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -2705,6 +4188,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2718,6 +4202,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2727,6 +4212,7 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -2736,15 +4222,30 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -2754,6 +4255,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2765,7 +4267,9 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2786,6 +4290,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -2798,6 +4303,7 @@ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "dev": true, + "license": "MIT", "dependencies": { "global-prefix": "^3.0.0" }, @@ -2810,6 +4316,7 @@ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", "dev": true, + "license": "MIT", "dependencies": { "ini": "^1.3.5", "kind-of": "^6.0.2", @@ -2824,6 +4331,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -2832,10 +4340,11 @@ } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -2851,6 +4360,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -2870,43 +4380,39 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -2914,47 +4420,19 @@ "node": ">= 0.4" } }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -2967,30 +4445,33 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/husky": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, + "license": "MIT", "bin": { - "husky": "lib/bin.js" + "husky": "bin.js" }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/typicode" } }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -3000,6 +4481,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -3011,20 +4493,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -3043,28 +4517,19 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" } }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3074,27 +4539,34 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3105,6 +4577,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3114,6 +4587,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3126,6 +4600,7 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3135,6 +4610,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -3147,6 +4623,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3156,24 +4633,17 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3183,6 +4653,7 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -3194,26 +4665,29 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", - "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" }, @@ -3221,26 +4695,12 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3248,17 +4708,12 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -3273,6 +4728,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -3283,10 +4739,11 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -3300,6 +4757,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -3326,6 +4784,7 @@ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", @@ -3340,6 +4799,7 @@ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -3371,6 +4831,7 @@ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -3404,6 +4865,7 @@ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", @@ -3449,6 +4911,7 @@ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -3464,6 +4927,7 @@ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, + "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -3476,6 +4940,7 @@ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -3492,6 +4957,7 @@ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -3509,6 +4975,7 @@ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -3518,6 +4985,7 @@ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -3543,6 +5011,7 @@ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" @@ -3556,6 +5025,7 @@ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -3571,6 +5041,7 @@ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -3591,6 +5062,7 @@ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -3605,6 +5077,7 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -3622,6 +5095,7 @@ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -3631,6 +5105,7 @@ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -3651,6 +5126,7 @@ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, + "license": "MIT", "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" @@ -3664,6 +5140,7 @@ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", @@ -3696,6 +5173,7 @@ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -3729,6 +5207,7 @@ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -3755,26 +5234,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3782,17 +5247,12 @@ "node": ">=10" } }, - "node_modules/jest-snapshot/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -3810,6 +5270,7 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -3827,6 +5288,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3839,6 +5301,7 @@ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", @@ -3858,6 +5321,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -3873,6 +5337,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3886,13 +5351,16 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -3901,46 +5369,52 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -3953,6 +5427,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -3962,6 +5437,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3971,21 +5447,24 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/known-css-properties": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", - "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==", - "dev": true + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", + "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", + "dev": true, + "license": "MIT" }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3995,6 +5474,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -4004,36 +5484,42 @@ } }, "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lint-staged": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.1.0.tgz", - "integrity": "sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==", - "dev": true, - "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "2.1.0", - "listr2": "7.0.2", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.4" + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.3.0.tgz", + "integrity": "sha512-vHFahytLoF2enJklgtOtCtIjZrKD/LoxlaUusd5nh7dWv/dkKQJY74ndFSzxCdv7g0ueGg1ORgTSt4Y9LPZn9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "~5.4.1", + "commander": "~12.1.0", + "debug": "~4.4.0", + "execa": "~8.0.1", + "lilconfig": "~3.1.3", + "listr2": "~8.2.5", + "micromatch": "~4.0.8", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.6.1" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -4046,10 +5532,11 @@ } }, "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -4062,6 +5549,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", @@ -4085,6 +5573,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -4097,6 +5586,7 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=16.17.0" } @@ -4106,6 +5596,7 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -4118,6 +5609,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4126,10 +5618,11 @@ } }, "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^4.0.0" }, @@ -4145,6 +5638,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^4.0.0" }, @@ -4160,6 +5654,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4172,6 +5667,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -4184,6 +5680,7 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4192,20 +5689,21 @@ } }, "node_modules/listr2": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", - "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", "dev": true, + "license": "MIT", "dependencies": { - "cli-truncate": "^3.1.0", + "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^5.0.1", - "rfdc": "^1.3.0", - "wrap-ansi": "^8.1.0" + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/locate-path": { @@ -4213,6 +5711,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -4223,57 +5722,76 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-update": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", - "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-escapes": "^5.0.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^5.0.0", - "strip-ansi": "^7.0.1", - "wrap-ansi": "^8.0.1" + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", - "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^1.0.2" + "environment": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4281,42 +5799,66 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/log-update/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==", + "node_modules/log-update/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, - "dependencies": { - "ansi-regex": "^6.0.1" - }, + "license": "MIT", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/log-update/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "license": "MIT", "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, - "bin": { - "loose-envify": "cli.js" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/lru-cache": { @@ -4324,15 +5866,28 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -4343,26 +5898,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4370,82 +5911,42 @@ "node": ">=10" } }, - "node_modules/make-dir/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mathml-tag-names": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/meow": { - "version": "10.1.5", - "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", - "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", "dev": true, - "dependencies": { - "@types/minimist": "^1.2.2", - "camelcase-keys": "^7.0.0", - "decamelize": "^5.0.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.2", - "read-pkg-up": "^8.0.0", - "redent": "^4.0.0", - "trim-newlines": "^4.0.2", - "type-fest": "^1.2.2", - "yargs-parser": "^20.2.9" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "CC0-1.0" }, - "node_modules/meow/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4455,24 +5956,27 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -4484,15 +5988,30 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -4502,6 +6021,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4509,30 +6029,17 @@ "node": "*" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, "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 + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { @@ -4540,6 +6047,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -4551,73 +6059,29 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "license": "MIT" }, "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, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4627,6 +6091,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -4639,6 +6104,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -4648,6 +6114,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -4659,17 +6126,18 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -4680,6 +6148,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -4695,6 +6164,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -4710,6 +6180,7 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4719,6 +6190,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -4731,6 +6203,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -4749,6 +6222,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4758,6 +6232,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4767,6 +6242,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4775,28 +6251,32 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -4809,6 +6289,7 @@ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, + "license": "MIT", "bin": { "pidtree": "bin/pidtree.js" }, @@ -4821,6 +6302,7 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -4830,6 +6312,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -4842,6 +6325,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4855,6 +6339,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -4867,6 +6352,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -4882,6 +6368,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -4890,9 +6377,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "funding": [ { @@ -4908,42 +6395,56 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==", - "dev": true + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", + "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==", + "dev": true, + "license": "MIT" }, "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=18.0" }, "peerDependencies": { - "postcss": "^8.3.3" + "postcss": "^8.4.31" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -4956,22 +6457,25 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -4987,6 +6491,7 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -5001,6 +6506,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5013,6 +6519,7 @@ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, + "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -5026,14 +6533,15 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -5044,7 +6552,8 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT" }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -5064,110 +6573,123 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, + "node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "node_modules/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0" + "scheduler": "^0.25.0" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "react": "^19.0.0" } }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" }, - "node_modules/read-pkg": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", - "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^1.0.1" + "regenerate": "^1.4.2" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/read-pkg-up": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", - "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "dev": true, + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "license": "MIT", "dependencies": { - "find-up": "^5.0.0", - "read-pkg": "^6.0.0", - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/runtime": "^7.8.4" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=4" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/redent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", - "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, - "dependencies": { - "indent-string": "^5.0.0", - "strip-indent": "^4.0.0" + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, "node_modules/require-directory": { @@ -5175,6 +6697,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5184,23 +6707,28 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5210,6 +6738,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -5222,6 +6751,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5231,56 +6761,92 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, + "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor/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, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -5310,15 +6876,23 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, + "node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "license": "MIT" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -5328,6 +6902,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -5340,6 +6915,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5348,19 +6924,22 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5370,6 +6949,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" @@ -5386,6 +6966,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5398,15 +6979,17 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -5416,54 +6999,25 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -5476,6 +7030,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5485,6 +7040,7 @@ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.19" } @@ -5494,6 +7050,7 @@ "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -5503,27 +7060,29 @@ } }, "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==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/string-width/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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5536,6 +7095,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -5551,6 +7111,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5563,6 +7124,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5572,30 +7134,17 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", - "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -5603,92 +7152,118 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", - "dev": true - }, "node_modules/stylelint": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.11.0.tgz", - "integrity": "sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==", + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz", + "integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^2.3.1", - "@csstools/css-tokenizer": "^2.2.0", - "@csstools/media-query-list-parser": "^2.1.4", - "@csstools/selector-specificity": "^3.0.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2", + "@csstools/selector-specificity": "^5.0.0", + "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^8.2.0", - "css-functions-list": "^3.2.1", - "css-tree": "^2.3.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.1", + "cosmiconfig": "^9.0.0", + "css-functions-list": "^3.2.3", + "css-tree": "^3.0.1", + "debug": "^4.3.7", + "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^7.0.0", + "file-entry-cache": "^9.1.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", - "ignore": "^5.2.4", - "import-lazy": "^4.0.0", + "ignore": "^6.0.2", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.29.0", + "known-css-properties": "^0.35.0", "mathml-tag-names": "^2.1.3", - "meow": "^10.1.5", - "micromatch": "^4.0.5", + "meow": "^13.2.0", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.28", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.13", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-safe-parser": "^7.0.1", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", - "supports-hyperlinks": "^3.0.0", + "supports-hyperlinks": "^3.1.0", "svg-tags": "^1.0.0", - "table": "^6.8.1", + "table": "^6.9.0", "write-file-atomic": "^5.0.1" }, "bin": { "stylelint": "bin/stylelint.mjs" }, "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" + "node": ">=18.12.0" } }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/stylelint/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.2.tgz", - "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz", + "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", + "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.2.0" + "flatted": "^3.3.1", + "keyv": "^4.5.4" }, "engines": { - "node": ">=12.0.0" + "node": ">=18" + } + }, + "node_modules/stylelint/node_modules/ignore": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", + "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" } }, "node_modules/stylelint/node_modules/is-fullwidth-code-point": { @@ -5696,6 +7271,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5705,6 +7281,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5714,6 +7291,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -5726,6 +7304,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5740,6 +7319,7 @@ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" @@ -5753,6 +7333,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5761,16 +7342,20 @@ } }, "node_modules/supports-hyperlinks": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", - "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz", + "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" }, "engines": { "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -5778,6 +7363,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5792,10 +7378,11 @@ "dev": true }, "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", @@ -5808,15 +7395,16 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -5827,13 +7415,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/table/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5842,13 +7432,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/table/node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -5866,6 +7458,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5880,6 +7473,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -5893,28 +7487,22 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "engines": { - "node": ">=4" - } + "license": "BSD-3-Clause" }, "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==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -5922,23 +7510,12 @@ "node": ">=8.0" } }, - "node_modules/trim-newlines": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", - "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -5951,6 +7528,7 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -5960,6 +7538,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -5968,15 +7547,60 @@ } }, "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 + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -5992,9 +7616,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -6008,6 +7633,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -6016,13 +7642,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -6032,21 +7660,12 @@ "node": ">=10.12.0" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } @@ -6056,6 +7675,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -6066,28 +7686,40 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "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==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrap-ansi/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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -6100,6 +7732,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -6112,6 +7745,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -6126,13 +7760,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -6146,6 +7782,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -6154,13 +7791,18 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", + "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } @@ -6170,6 +7812,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -6183,26 +7826,19 @@ "node": ">=12" } }, - "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" - } - }, "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6212,6 +7848,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -6226,6 +7863,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -6235,6 +7873,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/.github/test/node_test/package.json b/.github/test/node_test/package.json index e77ac4d..6a75cc3 100644 --- a/.github/test/node_test/package.json +++ b/.github/test/node_test/package.json @@ -23,12 +23,17 @@ "prepare": "cd ../../.. && husky install .husky" }, "devDependencies": { + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.1.0", + "babel-jest": "^29.7.0", "eslint": "^8.20.0", - "husky": "^8.0.1", - "jest": "^29.1.1", + "husky": "^9.1.7", + "jest": "^29.7.0", "lint-staged": "^15.1.0", "prettier": "^3.1.0", - "stylelint": "^15.2.0" + "stylelint": "^16.12.0" }, "lint_staged": { "*.{js,jsx}": [ @@ -41,6 +46,7 @@ ] }, "dependencies": { - "react": "^18.2.0" + "react": "^19.0.0", + "react-dom": "^19.0.0" } } diff --git a/.github/workflows/_node.yml b/.github/workflows/_node.yml index 97d8980..ec23789 100644 --- a/.github/workflows/_node.yml +++ b/.github/workflows/_node.yml @@ -102,7 +102,7 @@ jobs: if [[ '${{ inputs.use_jest }}' != 'false' ]]; then npm i -D --package-lock-only jest @testing-library/jest-dom babel-jest @babel/core @babel/preset-env if [[ '${{ inputs.use_react }}' != 'false' ]]; then - npm i -D --package-lock-only @testing-library/react @testing-library/jest-dom + npm i -D --package-lock-only @testing-library/react fi fi if [[ '${{ inputs.use_eslint }}' != 'false' ]]; then @@ -138,7 +138,7 @@ jobs: requirements: ${{ inputs.requirements_path }} external: ${{ inputs.working_directory }}/licenses.csv external-format: csv - table-headers: true + headers: true fail: 'StrongCopyleft,NetworkCopyleft,Error' fails-only: true diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index ac68e9a..fbf59eb 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -290,7 +290,7 @@ jobs: with: requirements: ${{ inputs.install_from }}/${{ inputs.requirements_path }} exclude: ${{ inputs.ignore_requirements_licenses_regex }} - table-headers: true + headers: true fail: 'StrongCopyleft,NetworkCopyleft,Error' fails-only: true @@ -320,7 +320,7 @@ jobs: if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then echo "flake8==7.1.1" >> requirements-linters.txt if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "flake8-django==1.4" >> requirements-linters.txt + echo "flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b" >> requirements-linters.txt fi fi diff --git a/workflows/_node.yml b/workflows/_node.yml index 97d8980..ec23789 100644 --- a/workflows/_node.yml +++ b/workflows/_node.yml @@ -102,7 +102,7 @@ jobs: if [[ '${{ inputs.use_jest }}' != 'false' ]]; then npm i -D --package-lock-only jest @testing-library/jest-dom babel-jest @babel/core @babel/preset-env if [[ '${{ inputs.use_react }}' != 'false' ]]; then - npm i -D --package-lock-only @testing-library/react @testing-library/jest-dom + npm i -D --package-lock-only @testing-library/react fi fi if [[ '${{ inputs.use_eslint }}' != 'false' ]]; then @@ -138,7 +138,7 @@ jobs: requirements: ${{ inputs.requirements_path }} external: ${{ inputs.working_directory }}/licenses.csv external-format: csv - table-headers: true + headers: true fail: 'StrongCopyleft,NetworkCopyleft,Error' fails-only: true diff --git a/workflows/_python.yml b/workflows/_python.yml index ac68e9a..fbf59eb 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -290,7 +290,7 @@ jobs: with: requirements: ${{ inputs.install_from }}/${{ inputs.requirements_path }} exclude: ${{ inputs.ignore_requirements_licenses_regex }} - table-headers: true + headers: true fail: 'StrongCopyleft,NetworkCopyleft,Error' fails-only: true @@ -320,7 +320,7 @@ jobs: if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then echo "flake8==7.1.1" >> requirements-linters.txt if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "flake8-django==1.4" >> requirements-linters.txt + echo "flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b" >> requirements-linters.txt fi fi From cf7c16d92f1015206b1dafb03df18be2d0fa1ead Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:59:49 +0100 Subject: [PATCH 03/15] Updated linters and added changes detection exclusions (#213) * Updated linters and added changes detection exclusions * Using ~ on linter versions * reinstated latest on ubuntu version field * added glob for backend/frontend exclusions * Updated CHANGELOG --- .../python_linters/requirements-linters.txt | 16 +- .github/workflows/_detect_changes.yml | 33 ++- .github/workflows/_node.yml | 8 +- .github/workflows/_python.yml | 270 +++++++++--------- .github/workflows/pull_request_automation.yml | 5 +- .pre-commit-config.yaml | 11 +- CHANGELOG.md | 15 + .../python_linters/requirements-linters.txt | 16 +- workflows/_detect_changes.yml | 33 ++- workflows/_node.yml | 8 +- workflows/_python.yml | 270 +++++++++--------- workflows/pull_request_automation.yml | 5 +- 12 files changed, 364 insertions(+), 326 deletions(-) diff --git a/.github/configurations/python_linters/requirements-linters.txt b/.github/configurations/python_linters/requirements-linters.txt index 39fb9e3..1f6b203 100644 --- a/.github/configurations/python_linters/requirements-linters.txt +++ b/.github/configurations/python_linters/requirements-linters.txt @@ -1,10 +1,8 @@ -autoflake==2.3.1 -bandit==1.7.9 -black==24.8.0 -# use fork since main repo is not updated -# see https://github.com/rocioar/flake8-django/pull/134 +autoflake~=2.3.1 +bandit~=1.8.3 +black~=25.1.0 flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b -flake8==7.1.1 -isort==5.13.2 -pylint-django==2.5.5 -pylint==3.2.6 \ No newline at end of file +flake8~=7.1.2 +isort~=6.0.1 +pylint-django~=2.6.1 +pylint~=3.3.5 \ No newline at end of file diff --git a/.github/workflows/_detect_changes.yml b/.github/workflows/_detect_changes.yml index efaffa0..eb68be3 100644 --- a/.github/workflows/_detect_changes.yml +++ b/.github/workflows/_detect_changes.yml @@ -6,13 +6,21 @@ on: description: Backend directories separated by spaces required: false type: string - default: '' + + backend_exclusions: + description: Backend directories or files to be excluded separated by spaces + required: false + type: string frontend_directories: description: Frontend directories separated by spaces required: false type: string - default: '' + + frontend_exclusions: + description: Frontend directories or files to be excluded separated by spaces + required: false + type: string ubuntu_version: description: Ubuntu version to use @@ -54,9 +62,18 @@ jobs: if: ${{inputs.backend_directories != ''}} id: diff_check_backend run: | - BACKEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} | head -n -1 | wc -l) + BACKEND_EXCLUSIONS="" + if ${{ inputs.backend_exclusions != ''}}; then + for exclusion in ${{ inputs.backend_exclusions }}; do + BACKEND_EXCLUSIONS+=":(glob,exclude)$exclusion " + done + fi + # No need to add other quotes since they will already be added. + BACKEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS | head -n -1 | wc -l) echo "backend=$BACKEND_CHANGES" >> $GITHUB_OUTPUT echo "Backend Changes: $BACKEND_CHANGES" >> $GITHUB_STEP_SUMMARY + echo "::debug::diff command:git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS" + echo "::debug::diff command results: $(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS | head -n -1 )" echo "backend $BACKEND_CHANGES" @@ -64,8 +81,16 @@ jobs: if: ${{inputs.frontend_directories != ''}} id: diff_check_frontend run: | - FRONTEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.frontend_directories }} | head -n -1 | wc -l) + FRONTEND_EXCLUSIONS="" + if ${{ inputs.frontend_exclusions != ''}}; then + for exclusion in ${{ inputs.frontend_exclusions }}; do + FRONTEND_EXCLUSIONS+=":(glob,exclude)$exclusion " + done + fi + FRONTEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.frontend_directories }} $FRONTEND_EXCLUSIONS | head -n -1 | wc -l) echo "frontend=$FRONTEND_CHANGES" >> $GITHUB_OUTPUT echo "Frontend Changes: $FRONTEND_CHANGES" >> $GITHUB_STEP_SUMMARY + echo "::debug::diff command:git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $FRONTEND_EXCLUSIONS" + echo "::debug::diff command results: $(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $FRONTEND_EXCLUSIONS | head -n -1 )" echo "frontend $FRONTEND_CHANGES" diff --git a/.github/workflows/_node.yml b/.github/workflows/_node.yml index ec23789..1a850b0 100644 --- a/.github/workflows/_node.yml +++ b/.github/workflows/_node.yml @@ -124,10 +124,10 @@ jobs: uses: ./.github/actions/node_linter with: working_directory: ${{ inputs.working_directory }} - use_eslint: ${{ inputs.use_eslint == true }} - use_prettier: ${{ inputs.use_prettier == true }} - use_stylelint: ${{ inputs.use_stylelint == true }} - check_packages_licenses: ${{ inputs.check_packages_licenses == true }} + use_eslint: ${{ inputs.use_eslint }} + use_prettier: ${{ inputs.use_prettier }} + use_stylelint: ${{ inputs.use_stylelint }} + check_packages_licenses: ${{ inputs.check_packages_licenses }} - name: Check packages licenses if: ${{ inputs.check_packages_licenses }} diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index fbf59eb..f8ae359 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -2,168 +2,159 @@ name: Reusable python linter workflow on: workflow_call: inputs: + # Base configs python_versions: - description: Python versions to use + description: Python versions to use (in the form of a JSON array) type: string required: true + ubuntu_version: + description: Ubuntu version to use + type: string + default: latest + required: false working_directory: description: Directory that must be run against the linters type: string required: true - - use_autoflake: - description: Use autoflake linter - default: false - type: boolean - required: false - use_black: - description: Use black formatter - default: false - type: boolean - required: false - use_isort: - description: Use isort formatter - default: false - type: boolean - required: false - use_flake8: - description: Use flake8 linter - default: false - type: boolean - required: false - use_pylint: - description: Use pylint linter - default: false - type: boolean - required: false - use_bandit: - description: Use bandit linter - default: false - type: boolean - required: false - - run_codeql: - description: Run codeql - default: false - type: boolean - required: false - requirements_path: description: Path to the requirements.txt file type: string required: true - install_from: description: Directory that must be used to install the packages type: string required: false default: . - packages_path: - description: Path to the packages.txt file + description: Path to the packages.txt file (APT requirements) type: string required: false - - custom_command: - description: String of custom command to run + env: + description: Environment variables to set type: string required: false - django_settings_module: - description: Path to the django settings file - type: string + default: >- + {} + max_timeout: + description: Max time that the CI can be run + type: number required: false - default: '' + default: 30 - check_migrations: - description: Check if migrations are valid. Require django_settings_module to be set. + # Formatters + use_black: + description: Use black formatter type: boolean required: false - default: false - check_requirements_licenses: - description: Check if requirements have a valid license. Require django_settings_module to be set. + use_isort: + description: Use isort formatter type: boolean required: false - default: true - ignore_requirements_licenses_regex: - description: Regex of repositories of which ignore license - type: string + + # Linters + use_autoflake: + description: Use autoflake linter + type: boolean + required: false + use_bandit: + description: Use bandit linter + type: boolean + required: false + use_flake8: + description: Use flake8 linter + type: boolean + required: false + use_pylint: + description: Use pylint linter + type: boolean required: false - default: uWSGI.*|lunardate.*|.*QuokkaClient.*|pyquokka.* - check_docs_directory: - description: Check docs using rstcheck inside this directory - type: string + # Coverage configs + use_coverage: + description: Use coverage.py. + type: boolean required: false - default: '' - check_dockerfile: - description: Check dockerfile build. WARNING action total time may increase significantly + coverage_config_path: + description: Path to the coverage.py config file type: string required: false - default: '' + default: .coveragerc + upload_coverage: + description: Upload coverage.py report to github + type: boolean + required: false - use_postgres: - description: Use postgres service - default: false + # CodeQL configs + run_codeql: + description: Run codeql + type: boolean + required: false + + # Services + use_celery: + description: Create a celery worker type: boolean required: false use_elastic_search: description: Use elastic_search service - default: false type: boolean required: false use_memcached: description: Use memcached service - default: false type: boolean required: false - use_redis: - description: Use redis service - default: false + use_mongo: + description: Use mongo service type: boolean required: false - use_rabbitmq: - description: Use rabbitmq service - default: false + use_postgres: + description: Use postgres service type: boolean required: false - use_mongo: - description: Use mongo service - default: false + use_rabbitmq: + description: Use rabbitmq service type: boolean required: false - use_celery: - description: Create a celery worker - default: false + use_redis: + description: Use redis service type: boolean required: false - use_coverage: - description: Use coverage.py. - default: false - type: boolean + # Services configs + ## Celery service configs + celery_app: + description: Celery app name. Requires use_celery to be true + type: string required: false - coverage_config_path: - description: Path to the coverage.py config file + celery_queues: + description: Celery queues separated by ,. Requires use_celery to be true type: string required: false - default: .coveragerc - upload_coverage: - description: Upload coverage.py report to github - default: false - type: boolean + default: default + ## Elasticsearch service configs + elasticsearch_version: + description: Elasticsearch container version + type: string required: false - - tags_for_slow_tests: - description: Tags for tests that will be run only on master/main branch, space separated. Can be used only for django projects. - default: slow + default: latest + elasticsearch_port: + description: Elasticsearch container port type: string required: false - tags_for_manual_tests: - description: Tags for tests that will not be run on the CI, space separated. Can be used only for django projects. - default: manual + default: 9200 + ## Memcached service configs + memcached_version: + description: Memcached alpine container version type: string required: false - + default: latest + ## Mongo service configs + mongo_version: + description: Mongo container version + type: string + required: false + default: latest + ## Postgres service configs postgres_db: description: Postgres service db. Requires use_postgres to be true type: string @@ -184,66 +175,63 @@ on: type: string required: false default: latest - - mongo_version: - description: Mongo container version + ## RabbitMQ service configs + rabbitmq_version: + description: RabbitMQ management-alpine container version type: string required: false default: latest - elasticsearch_version: - description: Elasticsearch container version + ## Redis service configs + redis_version: + description: Redis alpine container version type: string required: false - default: 8.11.1 - elasticsearch_port: - description: Elasticsearch container port + default: latest + + + # Django configs + django_settings_module: + description: Path to the django settings file type: string required: false - default: 9200 - memcached_version: - description: Memcached alpine container version - type: string + check_migrations: + description: Check if migrations are valid. Require django_settings_module to be set. + type: boolean required: false - default: latest - redis_version: - description: Redis alpine container version - type: string + check_requirements_licenses: + description: Check if requirements have a valid license. Require django_settings_module to be set. + type: boolean required: false - default: latest - rabbitmq_version: - description: RabbitMQ management-alpine container version + default: true + ignore_requirements_licenses_regex: + description: Regex of repositories of which ignore license type: string required: false - default: 3 - - celery_app: - description: Celery app name. Requires use_celery to be true + default: uWSGI.*|lunardate.*|.*QuokkaClient.*|pyquokka.* + tags_for_slow_tests: + description: Tags for tests that will be run only on master/main branch, space separated. Can be used only for django projects. + default: slow type: string required: false - - celery_queues: - description: Celery queues separated by ,. Requires use_celery to be true + tags_for_manual_tests: + description: Tags for tests that will not be run on the CI, space separated. Can be used only for django projects. + default: manual type: string required: false - default: default - env: - description: Environment variables to set + # Misc configs + custom_command: + description: String of custom command to run type: string required: false - default: >- - {} - max_timeout: - description: Max time that the CI can be run - type: number + check_docs_directory: + description: Check docs using rstcheck inside this directory + type: string required: false - default: 30 - - ubuntu_version: - description: Ubuntu version to use + check_dockerfile: + description: Check dockerfile build. WARNING action total time may increase significantly type: string - default: latest required: false jobs: diff --git a/.github/workflows/pull_request_automation.yml b/.github/workflows/pull_request_automation.yml index c1a29b0..5ec92ee 100644 --- a/.github/workflows/pull_request_automation.yml +++ b/.github/workflows/pull_request_automation.yml @@ -22,7 +22,6 @@ jobs: ubuntu_version: latest - node: needs: detect-changes if: ${{ needs.detect-changes.outputs.frontend > 0 }} @@ -45,9 +44,9 @@ jobs: use_coverage: true upload_coverage: true max_timeout: 15 - ubuntu_version: 22.04 node_versions: >- ["20"] + ubuntu_version: latest python: @@ -105,4 +104,4 @@ jobs: python_versions: >- ["3.10"] max_timeout: 15 - ubuntu_version: 22.04 + ubuntu_version: latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9aa1555..c845ce3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,26 +11,29 @@ repos: args: ["--rcfile", ".github/configurations/python_linters/.pylintrc"] - repo: https://github.com/pycqa/bandit - rev: 1.7.9 + rev: 1.8.3 hooks: - id: bandit args: ["-c", ".github/configurations/python_linters/.bandit.yaml"] - repo: https://github.com/pycqa/flake8 - rev: 7.1.1 + rev: 7.1.2 hooks: - id: flake8 exclude: docs/conf.py args: ["--config", ".github/configurations/python_linters/.flake8"] + # use fork since main repo is not updated + # see https://github.com/rocioar/flake8-django/pull/134 + additional_dependencies: ["git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b"] - repo: https://github.com/pycqa/isort - rev: 5.13.2 + rev: 6.0.1 hooks: - id: isort args: ["--settings-path", ".github/configurations/python_linters/.isort.cfg", "--filter-files", "--skip", "venv"] - repo: https://github.com/psf/black - rev: 24.8.0 + rev: 25.1.0 hooks: - id: black args: ["--config", ".github/configurations/python_linters/.black"] diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29..dfa53ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# 1.6.x +## 1.6.0 +### Features + +* Added both frontend and backend exclusions on _detect_changes.yaml (paths that won't be considered by git diff) + +### Changes + +* Updated Python linters: + * bandit 1.7.9 -> 1.8.3 + * black 24.8.0 -> 25.1.0 + * flake8 7.1.1 -> 7.1.2 + * isort 5.13.2 -> 6.0.1 + * pylint-django 2.5.5 -> 2.6.1 + * pylint 3.2.6 -> 3.3.5 diff --git a/configurations/python_linters/requirements-linters.txt b/configurations/python_linters/requirements-linters.txt index 39fb9e3..1f6b203 100644 --- a/configurations/python_linters/requirements-linters.txt +++ b/configurations/python_linters/requirements-linters.txt @@ -1,10 +1,8 @@ -autoflake==2.3.1 -bandit==1.7.9 -black==24.8.0 -# use fork since main repo is not updated -# see https://github.com/rocioar/flake8-django/pull/134 +autoflake~=2.3.1 +bandit~=1.8.3 +black~=25.1.0 flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b -flake8==7.1.1 -isort==5.13.2 -pylint-django==2.5.5 -pylint==3.2.6 \ No newline at end of file +flake8~=7.1.2 +isort~=6.0.1 +pylint-django~=2.6.1 +pylint~=3.3.5 \ No newline at end of file diff --git a/workflows/_detect_changes.yml b/workflows/_detect_changes.yml index efaffa0..eb68be3 100644 --- a/workflows/_detect_changes.yml +++ b/workflows/_detect_changes.yml @@ -6,13 +6,21 @@ on: description: Backend directories separated by spaces required: false type: string - default: '' + + backend_exclusions: + description: Backend directories or files to be excluded separated by spaces + required: false + type: string frontend_directories: description: Frontend directories separated by spaces required: false type: string - default: '' + + frontend_exclusions: + description: Frontend directories or files to be excluded separated by spaces + required: false + type: string ubuntu_version: description: Ubuntu version to use @@ -54,9 +62,18 @@ jobs: if: ${{inputs.backend_directories != ''}} id: diff_check_backend run: | - BACKEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} | head -n -1 | wc -l) + BACKEND_EXCLUSIONS="" + if ${{ inputs.backend_exclusions != ''}}; then + for exclusion in ${{ inputs.backend_exclusions }}; do + BACKEND_EXCLUSIONS+=":(glob,exclude)$exclusion " + done + fi + # No need to add other quotes since they will already be added. + BACKEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS | head -n -1 | wc -l) echo "backend=$BACKEND_CHANGES" >> $GITHUB_OUTPUT echo "Backend Changes: $BACKEND_CHANGES" >> $GITHUB_STEP_SUMMARY + echo "::debug::diff command:git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS" + echo "::debug::diff command results: $(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS | head -n -1 )" echo "backend $BACKEND_CHANGES" @@ -64,8 +81,16 @@ jobs: if: ${{inputs.frontend_directories != ''}} id: diff_check_frontend run: | - FRONTEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.frontend_directories }} | head -n -1 | wc -l) + FRONTEND_EXCLUSIONS="" + if ${{ inputs.frontend_exclusions != ''}}; then + for exclusion in ${{ inputs.frontend_exclusions }}; do + FRONTEND_EXCLUSIONS+=":(glob,exclude)$exclusion " + done + fi + FRONTEND_CHANGES=$(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.frontend_directories }} $FRONTEND_EXCLUSIONS | head -n -1 | wc -l) echo "frontend=$FRONTEND_CHANGES" >> $GITHUB_OUTPUT echo "Frontend Changes: $FRONTEND_CHANGES" >> $GITHUB_STEP_SUMMARY + echo "::debug::diff command:git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $FRONTEND_EXCLUSIONS" + echo "::debug::diff command results: $(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $FRONTEND_EXCLUSIONS | head -n -1 )" echo "frontend $FRONTEND_CHANGES" diff --git a/workflows/_node.yml b/workflows/_node.yml index ec23789..1a850b0 100644 --- a/workflows/_node.yml +++ b/workflows/_node.yml @@ -124,10 +124,10 @@ jobs: uses: ./.github/actions/node_linter with: working_directory: ${{ inputs.working_directory }} - use_eslint: ${{ inputs.use_eslint == true }} - use_prettier: ${{ inputs.use_prettier == true }} - use_stylelint: ${{ inputs.use_stylelint == true }} - check_packages_licenses: ${{ inputs.check_packages_licenses == true }} + use_eslint: ${{ inputs.use_eslint }} + use_prettier: ${{ inputs.use_prettier }} + use_stylelint: ${{ inputs.use_stylelint }} + check_packages_licenses: ${{ inputs.check_packages_licenses }} - name: Check packages licenses if: ${{ inputs.check_packages_licenses }} diff --git a/workflows/_python.yml b/workflows/_python.yml index fbf59eb..f8ae359 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -2,168 +2,159 @@ name: Reusable python linter workflow on: workflow_call: inputs: + # Base configs python_versions: - description: Python versions to use + description: Python versions to use (in the form of a JSON array) type: string required: true + ubuntu_version: + description: Ubuntu version to use + type: string + default: latest + required: false working_directory: description: Directory that must be run against the linters type: string required: true - - use_autoflake: - description: Use autoflake linter - default: false - type: boolean - required: false - use_black: - description: Use black formatter - default: false - type: boolean - required: false - use_isort: - description: Use isort formatter - default: false - type: boolean - required: false - use_flake8: - description: Use flake8 linter - default: false - type: boolean - required: false - use_pylint: - description: Use pylint linter - default: false - type: boolean - required: false - use_bandit: - description: Use bandit linter - default: false - type: boolean - required: false - - run_codeql: - description: Run codeql - default: false - type: boolean - required: false - requirements_path: description: Path to the requirements.txt file type: string required: true - install_from: description: Directory that must be used to install the packages type: string required: false default: . - packages_path: - description: Path to the packages.txt file + description: Path to the packages.txt file (APT requirements) type: string required: false - - custom_command: - description: String of custom command to run + env: + description: Environment variables to set type: string required: false - django_settings_module: - description: Path to the django settings file - type: string + default: >- + {} + max_timeout: + description: Max time that the CI can be run + type: number required: false - default: '' + default: 30 - check_migrations: - description: Check if migrations are valid. Require django_settings_module to be set. + # Formatters + use_black: + description: Use black formatter type: boolean required: false - default: false - check_requirements_licenses: - description: Check if requirements have a valid license. Require django_settings_module to be set. + use_isort: + description: Use isort formatter type: boolean required: false - default: true - ignore_requirements_licenses_regex: - description: Regex of repositories of which ignore license - type: string + + # Linters + use_autoflake: + description: Use autoflake linter + type: boolean + required: false + use_bandit: + description: Use bandit linter + type: boolean + required: false + use_flake8: + description: Use flake8 linter + type: boolean + required: false + use_pylint: + description: Use pylint linter + type: boolean required: false - default: uWSGI.*|lunardate.*|.*QuokkaClient.*|pyquokka.* - check_docs_directory: - description: Check docs using rstcheck inside this directory - type: string + # Coverage configs + use_coverage: + description: Use coverage.py. + type: boolean required: false - default: '' - check_dockerfile: - description: Check dockerfile build. WARNING action total time may increase significantly + coverage_config_path: + description: Path to the coverage.py config file type: string required: false - default: '' + default: .coveragerc + upload_coverage: + description: Upload coverage.py report to github + type: boolean + required: false - use_postgres: - description: Use postgres service - default: false + # CodeQL configs + run_codeql: + description: Run codeql + type: boolean + required: false + + # Services + use_celery: + description: Create a celery worker type: boolean required: false use_elastic_search: description: Use elastic_search service - default: false type: boolean required: false use_memcached: description: Use memcached service - default: false type: boolean required: false - use_redis: - description: Use redis service - default: false + use_mongo: + description: Use mongo service type: boolean required: false - use_rabbitmq: - description: Use rabbitmq service - default: false + use_postgres: + description: Use postgres service type: boolean required: false - use_mongo: - description: Use mongo service - default: false + use_rabbitmq: + description: Use rabbitmq service type: boolean required: false - use_celery: - description: Create a celery worker - default: false + use_redis: + description: Use redis service type: boolean required: false - use_coverage: - description: Use coverage.py. - default: false - type: boolean + # Services configs + ## Celery service configs + celery_app: + description: Celery app name. Requires use_celery to be true + type: string required: false - coverage_config_path: - description: Path to the coverage.py config file + celery_queues: + description: Celery queues separated by ,. Requires use_celery to be true type: string required: false - default: .coveragerc - upload_coverage: - description: Upload coverage.py report to github - default: false - type: boolean + default: default + ## Elasticsearch service configs + elasticsearch_version: + description: Elasticsearch container version + type: string required: false - - tags_for_slow_tests: - description: Tags for tests that will be run only on master/main branch, space separated. Can be used only for django projects. - default: slow + default: latest + elasticsearch_port: + description: Elasticsearch container port type: string required: false - tags_for_manual_tests: - description: Tags for tests that will not be run on the CI, space separated. Can be used only for django projects. - default: manual + default: 9200 + ## Memcached service configs + memcached_version: + description: Memcached alpine container version type: string required: false - + default: latest + ## Mongo service configs + mongo_version: + description: Mongo container version + type: string + required: false + default: latest + ## Postgres service configs postgres_db: description: Postgres service db. Requires use_postgres to be true type: string @@ -184,66 +175,63 @@ on: type: string required: false default: latest - - mongo_version: - description: Mongo container version + ## RabbitMQ service configs + rabbitmq_version: + description: RabbitMQ management-alpine container version type: string required: false default: latest - elasticsearch_version: - description: Elasticsearch container version + ## Redis service configs + redis_version: + description: Redis alpine container version type: string required: false - default: 8.11.1 - elasticsearch_port: - description: Elasticsearch container port + default: latest + + + # Django configs + django_settings_module: + description: Path to the django settings file type: string required: false - default: 9200 - memcached_version: - description: Memcached alpine container version - type: string + check_migrations: + description: Check if migrations are valid. Require django_settings_module to be set. + type: boolean required: false - default: latest - redis_version: - description: Redis alpine container version - type: string + check_requirements_licenses: + description: Check if requirements have a valid license. Require django_settings_module to be set. + type: boolean required: false - default: latest - rabbitmq_version: - description: RabbitMQ management-alpine container version + default: true + ignore_requirements_licenses_regex: + description: Regex of repositories of which ignore license type: string required: false - default: 3 - - celery_app: - description: Celery app name. Requires use_celery to be true + default: uWSGI.*|lunardate.*|.*QuokkaClient.*|pyquokka.* + tags_for_slow_tests: + description: Tags for tests that will be run only on master/main branch, space separated. Can be used only for django projects. + default: slow type: string required: false - - celery_queues: - description: Celery queues separated by ,. Requires use_celery to be true + tags_for_manual_tests: + description: Tags for tests that will not be run on the CI, space separated. Can be used only for django projects. + default: manual type: string required: false - default: default - env: - description: Environment variables to set + # Misc configs + custom_command: + description: String of custom command to run type: string required: false - default: >- - {} - max_timeout: - description: Max time that the CI can be run - type: number + check_docs_directory: + description: Check docs using rstcheck inside this directory + type: string required: false - default: 30 - - ubuntu_version: - description: Ubuntu version to use + check_dockerfile: + description: Check dockerfile build. WARNING action total time may increase significantly type: string - default: latest required: false jobs: diff --git a/workflows/pull_request_automation.yml b/workflows/pull_request_automation.yml index c1a29b0..5ec92ee 100644 --- a/workflows/pull_request_automation.yml +++ b/workflows/pull_request_automation.yml @@ -22,7 +22,6 @@ jobs: ubuntu_version: latest - node: needs: detect-changes if: ${{ needs.detect-changes.outputs.frontend > 0 }} @@ -45,9 +44,9 @@ jobs: use_coverage: true upload_coverage: true max_timeout: 15 - ubuntu_version: 22.04 node_versions: >- ["20"] + ubuntu_version: latest python: @@ -105,4 +104,4 @@ jobs: python_versions: >- ["3.10"] max_timeout: 15 - ubuntu_version: 22.04 + ubuntu_version: latest From 5f44be836bed04e79b7aeb66a5dd341115032034 Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:04:13 +0100 Subject: [PATCH 04/15] APT caching revisited (#214) --- .github/actions/apt_requirements/action.yml | 53 ++++++++++++++++----- .github/workflows/create_apt_cache.yaml | 39 +++++++++++++++ CHANGELOG.md | 4 +- actions/apt_requirements/action.yml | 53 ++++++++++++++++----- workflows/create_apt_cache.yaml | 39 +++++++++++++++ 5 files changed, 163 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/create_apt_cache.yaml create mode 100644 workflows/create_apt_cache.yaml diff --git a/.github/actions/apt_requirements/action.yml b/.github/actions/apt_requirements/action.yml index 872cbe5..0024e2c 100644 --- a/.github/actions/apt_requirements/action.yml +++ b/.github/actions/apt_requirements/action.yml @@ -1,9 +1,6 @@ -name: Composite action install apt requirements +name: Composite action install apt requirements description: Composite action install apt requirements inputs: - working_directory: - description: Working directory - required: true requirements_file: description: Requirements file required: true @@ -11,15 +8,47 @@ inputs: runs: using: "composite" steps: - - name: Export apt requirements - id: export-apt-requirements + - name: Compute APT requirements file SHA256 hash + id: compute_apt_requirements_file_sha256_hash + run: | + COMPUTED_HASH=$(sha256sum ${{ inputs.requirements_file }} | cut -d ' ' -f 1) + echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT + shell: bash + + # Vital to be able to restore cache + # If write permission is not set, a permissions error will be raised + - name: Modification to /var/cache/apt/archives permissions run: | - PKG=$(cat ${{ inputs.requirements_file }}) - echo apt_packages=$PKG | awk '{print}' ORS=' ' >> $GITHUB_OUTPUT + sudo chmod a+w /var/cache/apt/archives shell: bash - - name: Cache apt packages - id: cache-apt-packages - uses: awalsh128/cache-apt-pkgs-action@latest + - uses: actions/cache/restore@v4 + id: restore_cache_from_parent_branch + with: + path: /var/cache/apt/archives/*.deb + key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + + - uses: actions/cache/restore@v4 + id: restore_cache_from_current_branch + if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' + with: + path: /var/cache/apt/archives/*.deb + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + + - name: Refresh repositories + if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' + run: | + sudo apt-get update + shell: bash + + - name: Install requirements + run: | + sudo apt-get install -y --no-install-recommends $(tr '\n' ' ' < ${{ inputs.requirements_file }}) + shell: bash + + - uses: actions/cache/save@v4 + id: cache_apt_requirements_for_current_branch + if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' with: - packages: ${{ steps.export-apt-requirements.outputs.apt_packages }} \ No newline at end of file + path: /var/cache/apt/archives/*.deb + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} \ No newline at end of file diff --git a/.github/workflows/create_apt_cache.yaml b/.github/workflows/create_apt_cache.yaml new file mode 100644 index 0000000..2315fc9 --- /dev/null +++ b/.github/workflows/create_apt_cache.yaml @@ -0,0 +1,39 @@ +name: Create APT cache + +# GitHub will remove any cache entries that have not been accessed in over 7 days. + +on: + push: + branches: + - main + - master + - develop + - dev + paths: + # Path to APT requirements file + - '.github/test/python_test/packages.txt' + + +jobs: + create-cache: + name: Create cache for dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Remember to set the same APT requirements file path set before! + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < apt_packages.txt) + + - name: Compute apt_packages.txt SHA256 hash + id: compute_apt_packages_sha256_hash + run: | + COMPUTED_HASH=$(sha256sum apt_packages.txt | cut -d ' ' -f 1) + echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT + + - uses: actions/cache/save@v4 + with: + path: /var/cache/apt/archives/*.deb + key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.cache_key }} diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa53ad..1eec48a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 1.6.0 ### Features -* Added both frontend and backend exclusions on _detect_changes.yaml (paths that won't be considered by git diff) +* Added *create_apt_cache.yaml* workflow to cache APT requirements each time a commit is pushed on selected branch and **when the requirements file has changed**. ### Changes @@ -13,3 +13,5 @@ * isort 5.13.2 -> 6.0.1 * pylint-django 2.5.5 -> 2.6.1 * pylint 3.2.6 -> 3.3.5 +* Removed `awalsh128/cache-apt-pkgs-action@latest` action and rewrote APT caching using GitHub's `actions/cache/restore@v4` and `actions/cache/save@v4`. +* Added both frontend and backend exclusions on _detect_changes.yaml (paths that won't be considered by git diff) diff --git a/actions/apt_requirements/action.yml b/actions/apt_requirements/action.yml index 872cbe5..0024e2c 100644 --- a/actions/apt_requirements/action.yml +++ b/actions/apt_requirements/action.yml @@ -1,9 +1,6 @@ -name: Composite action install apt requirements +name: Composite action install apt requirements description: Composite action install apt requirements inputs: - working_directory: - description: Working directory - required: true requirements_file: description: Requirements file required: true @@ -11,15 +8,47 @@ inputs: runs: using: "composite" steps: - - name: Export apt requirements - id: export-apt-requirements + - name: Compute APT requirements file SHA256 hash + id: compute_apt_requirements_file_sha256_hash + run: | + COMPUTED_HASH=$(sha256sum ${{ inputs.requirements_file }} | cut -d ' ' -f 1) + echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT + shell: bash + + # Vital to be able to restore cache + # If write permission is not set, a permissions error will be raised + - name: Modification to /var/cache/apt/archives permissions run: | - PKG=$(cat ${{ inputs.requirements_file }}) - echo apt_packages=$PKG | awk '{print}' ORS=' ' >> $GITHUB_OUTPUT + sudo chmod a+w /var/cache/apt/archives shell: bash - - name: Cache apt packages - id: cache-apt-packages - uses: awalsh128/cache-apt-pkgs-action@latest + - uses: actions/cache/restore@v4 + id: restore_cache_from_parent_branch + with: + path: /var/cache/apt/archives/*.deb + key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + + - uses: actions/cache/restore@v4 + id: restore_cache_from_current_branch + if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' + with: + path: /var/cache/apt/archives/*.deb + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + + - name: Refresh repositories + if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' + run: | + sudo apt-get update + shell: bash + + - name: Install requirements + run: | + sudo apt-get install -y --no-install-recommends $(tr '\n' ' ' < ${{ inputs.requirements_file }}) + shell: bash + + - uses: actions/cache/save@v4 + id: cache_apt_requirements_for_current_branch + if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' with: - packages: ${{ steps.export-apt-requirements.outputs.apt_packages }} \ No newline at end of file + path: /var/cache/apt/archives/*.deb + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} \ No newline at end of file diff --git a/workflows/create_apt_cache.yaml b/workflows/create_apt_cache.yaml new file mode 100644 index 0000000..2315fc9 --- /dev/null +++ b/workflows/create_apt_cache.yaml @@ -0,0 +1,39 @@ +name: Create APT cache + +# GitHub will remove any cache entries that have not been accessed in over 7 days. + +on: + push: + branches: + - main + - master + - develop + - dev + paths: + # Path to APT requirements file + - '.github/test/python_test/packages.txt' + + +jobs: + create-cache: + name: Create cache for dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Remember to set the same APT requirements file path set before! + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < apt_packages.txt) + + - name: Compute apt_packages.txt SHA256 hash + id: compute_apt_packages_sha256_hash + run: | + COMPUTED_HASH=$(sha256sum apt_packages.txt | cut -d ' ' -f 1) + echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT + + - uses: actions/cache/save@v4 + with: + path: /var/cache/apt/archives/*.deb + key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.cache_key }} From ed2dd168a34364f77f902ee4b26c5199a62ca477 Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:08:34 +0100 Subject: [PATCH 05/15] Updated codeQL action to v3 (#216) * Updated codeQL action to v3 * Remove useless parameter from codeQL action --- .github/actions/codeql/action.yml | 5 ++--- CHANGELOG.md | 2 ++ actions/codeql/action.yml | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/codeql/action.yml b/.github/actions/codeql/action.yml index b49e2b6..22c16e1 100644 --- a/.github/actions/codeql/action.yml +++ b/.github/actions/codeql/action.yml @@ -12,13 +12,12 @@ runs: using: "composite" steps: - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ inputs.language }} - setup-python-dependencies: false source-root: ${{ inputs.working_directory }} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eec48a..c336b82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,3 +15,5 @@ * pylint 3.2.6 -> 3.3.5 * Removed `awalsh128/cache-apt-pkgs-action@latest` action and rewrote APT caching using GitHub's `actions/cache/restore@v4` and `actions/cache/save@v4`. * Added both frontend and backend exclusions on _detect_changes.yaml (paths that won't be considered by git diff) +* Updated CodeQL action v2 -> v3 (v2 has been [deprecated](https://github.blog/changelog/2024-01-12-code-scanning-deprecation-of-codeql-action-v2/) on december '24) +* Removed `setup-python-dependencies` from `codeql/action.yml` since it has no effect anymore. See [this](https://github.blog/changelog/2024-01-23-codeql-2-16-python-dependency-installation-disabled-new-queries-and-bug-fixes/) for more information. diff --git a/actions/codeql/action.yml b/actions/codeql/action.yml index b49e2b6..22c16e1 100644 --- a/actions/codeql/action.yml +++ b/actions/codeql/action.yml @@ -12,13 +12,12 @@ runs: using: "composite" steps: - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ inputs.language }} - setup-python-dependencies: false source-root: ${{ inputs.working_directory }} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 0cfa137b64e79eaaf3560cb15dd5a5dcc2e03d8d Mon Sep 17 00:00:00 2001 From: Simone Berni Date: Wed, 19 Mar 2025 11:43:45 +0100 Subject: [PATCH 06/15] Ecr (#201) * Ecr Signed-off-by: 0ssigeno * Ecr Signed-off-by: 0ssigeno * Fix Signed-off-by: 0ssigeno * Fix Signed-off-by: 0ssigeno * Fix Signed-off-by: 0ssigeno * Typo Signed-off-by: 0ssigeno * Fix role Signed-off-by: 0ssigeno * Fix Signed-off-by: 0ssigeno * Fix dockerfile Signed-off-by: 0ssigeno * Fixes Signed-off-by: 0ssigeno * Fixes Signed-off-by: 0ssigeno * Tab Signed-off-by: 0ssigeno * Fix Signed-off-by: 0ssigeno * Fix Signed-off-by: 0ssigeno * Test Signed-off-by: 0ssigeno * Cache system Signed-off-by: 0ssigeno * Fix Signed-off-by: 0ssigeno * Removed env Signed-off-by: 0ssigeno * Real branch Signed-off-by: 0ssigeno * Added test tag Signed-off-by: 0ssigeno * Disabled 'publish_on_ecr' by default --------- Signed-off-by: 0ssigeno Co-authored-by: Eugenio Severi Co-authored-by: eugenioseveri --- .github/actions/push_on_ecr/action.yml | 56 +++++++++++++++ .github/workflows/_python.yml | 6 -- .github/workflows/_release_and_tag.yml | 72 ++++++++++++++++++- .github/workflows/pull_request_automation.yml | 1 - .github/workflows/release.yml | 6 ++ actions/push_on_ecr/action.yml | 56 +++++++++++++++ workflows/_python.yml | 6 -- workflows/_release_and_tag.yml | 72 ++++++++++++++++++- workflows/pull_request_automation.yml | 1 - workflows/release.yml | 6 ++ 10 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 .github/actions/push_on_ecr/action.yml create mode 100644 actions/push_on_ecr/action.yml diff --git a/.github/actions/push_on_ecr/action.yml b/.github/actions/push_on_ecr/action.yml new file mode 100644 index 0000000..f130e59 --- /dev/null +++ b/.github/actions/push_on_ecr/action.yml @@ -0,0 +1,56 @@ +name: Composite action push on ecr +description: Composite action push on ecr +inputs: + repository: + description: Repository name + required: true + dockerfile: + description: Path for dockerfile from working directory + required: true + working_directory: + description: Docker build context + required: true + + aws_account_id: + description: Aws User code + required: true + aws_access_key: + description: Aws access key + required: true + aws_secret_access_key: + description: Aws secret access key + required: true + image_tag: + description: Directory that must be run against the linters + required: true + + aws_region: + description: Aws region + required: true + +runs: + using: "composite" + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ inputs.aws_region}} + aws-access-key-id: ${{ inputs.aws_access_key }} + aws-secret-access-key: ${{ inputs.aws_secret_access_key }} + + - name: Login to Amazon ECR Private + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: ${{ inputs.working_directory }} + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: ${{inputs.aws_account_id}}.dkr.ecr.${{inputs.aws_region}}.amazonaws.com/${{ inputs.repository }}:${{ inputs.image_tag }} + file: ${{ inputs.working_directory }}/${{ inputs.dockerfile }} diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index f8ae359..8e67133 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -412,12 +412,6 @@ jobs: shell: bash working-directory: ${{ inputs.check_docs_directory }} - - name: Build DockerFile - if: inputs.check_dockerfile - run: | - docker build -f ${{ inputs.check_dockerfile }} . - working-directory: ${{ inputs.working_directory }} - - name: Start services uses: ./.github/actions/services if: inputs.use_postgres || inputs.use_elastic_search || inputs.use_memcached || inputs.use_redis || inputs.use_rabbitmq || inputs.use_mongo diff --git a/.github/workflows/_release_and_tag.yml b/.github/workflows/_release_and_tag.yml index acc8181..aaa5124 100644 --- a/.github/workflows/_release_and_tag.yml +++ b/.github/workflows/_release_and_tag.yml @@ -31,11 +31,40 @@ on: required: false default: #CyberSecurity + publish_on_ecr: + description: Publish on ecr + type: boolean + required: false + default: false + repository: + description: Repository name + type: string + required: false + default: ${{ github.event.repository.name }} + + dockerfiles: + description: Path for dockerfiles from working directory + type: string + required: false + working_directory: + description: Docker build context + type: string + required: false + default: . + aws_region: + description: Aws region + type: string + required: false + default: eu-central-1 + + jobs: release_and_tag: name: Create release and tag runs-on: ubuntu-latest - if: github.event.pull_request.merged == true && ( github.base_ref == 'master' || github.base_ref == 'main' ) + if: github.event.pull_request.merged == true + outputs: + match: ${{ steps.check-tag.outputs.match }} steps: - uses: actions/checkout@v4 with: @@ -43,6 +72,7 @@ jobs: - name: Check Tag id: check-tag + if: github.base_ref == 'master' || github.base_ref == 'main' run: | if [[ "${{ github.event.pull_request.title }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "match=true" >> $GITHUB_OUTPUT @@ -115,4 +145,42 @@ jobs: api_key: ${{ secrets.TWITTER_API_KEY }} api_key_secret: ${{ secrets.TWITTER_API_KEY_SECRET }} access_token: ${{ secrets.TWITTER_ACCESS_TOKEN }} - access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} \ No newline at end of file + access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + + + push_on_ecr: + runs-on: ubuntu-latest + needs: release_and_tag + if: github.event.pull_request.merged == true && inputs.publish_on_ecr == true + strategy: + matrix: + dockerfile: ${{ fromJson(inputs.dockerfiles) }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # otherwise, you do not retrieve the tags + - name: Push on ecr branch + uses: ./.github/actions/push_on_ecr + if: github.base_ref == 'master' || github.base_ref == 'main' || github.base_ref == 'develop' || github.base_ref == 'dev' || github.base_ref == 'test' + with: + repository: ${{ inputs.repository }} + aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }} + aws_access_key: ${{ secrets.AWS_ACCESS_KEY}} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + dockerfile: ${{ matrix.dockerfile }} + image_tag: ${{ ( github.base_ref == 'main' || github.base_ref == 'master' ) && 'prod' || ( github.base_ref == 'develop' || github.base_ref == 'dev' ) && 'stag' || 'test' }} + aws_region: ${{ inputs.aws_region }} + working_directory: ${{ inputs.working_directory }} + + - name: Push on ecr new release + if: needs.release_and_tag.outputs.match == 'true' && (github.base_ref == 'master' || github.base_ref == 'main' ) + uses: ./.github/actions/push_on_ecr + with: + repository: ${{ inputs.repository }} + aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }} + aws_access_key: ${{ secrets.AWS_ACCESS_KEY}} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + dockerfile: ${{ inputs.dockerfile }} + image_tag: ${{ github.event.pull_request.title }} + aws_region: ${{ inputs.aws_region }} + working_directory: ${{ inputs.working_directory }} \ No newline at end of file diff --git a/.github/workflows/pull_request_automation.yml b/.github/workflows/pull_request_automation.yml index 5ec92ee..7c3ffb4 100644 --- a/.github/workflows/pull_request_automation.yml +++ b/.github/workflows/pull_request_automation.yml @@ -72,7 +72,6 @@ jobs: check_migrations: true check_requirements_licenses: true check_docs_directory: - check_dockerfile: Dockerfile use_postgres: false postgres_db: db diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4987b88..7288a8c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,3 +20,9 @@ jobs: publish_on_test_pypi: false publish_on_npm: false publish_on_twitter: false + publish_on_ecr: false + repository: certego-test + working_directory: .github/test/python_test + dockerfiles: >- + ["Dockerfile"] + aws_region: eu-central-1 diff --git a/actions/push_on_ecr/action.yml b/actions/push_on_ecr/action.yml new file mode 100644 index 0000000..f130e59 --- /dev/null +++ b/actions/push_on_ecr/action.yml @@ -0,0 +1,56 @@ +name: Composite action push on ecr +description: Composite action push on ecr +inputs: + repository: + description: Repository name + required: true + dockerfile: + description: Path for dockerfile from working directory + required: true + working_directory: + description: Docker build context + required: true + + aws_account_id: + description: Aws User code + required: true + aws_access_key: + description: Aws access key + required: true + aws_secret_access_key: + description: Aws secret access key + required: true + image_tag: + description: Directory that must be run against the linters + required: true + + aws_region: + description: Aws region + required: true + +runs: + using: "composite" + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ inputs.aws_region}} + aws-access-key-id: ${{ inputs.aws_access_key }} + aws-secret-access-key: ${{ inputs.aws_secret_access_key }} + + - name: Login to Amazon ECR Private + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: ${{ inputs.working_directory }} + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: ${{inputs.aws_account_id}}.dkr.ecr.${{inputs.aws_region}}.amazonaws.com/${{ inputs.repository }}:${{ inputs.image_tag }} + file: ${{ inputs.working_directory }}/${{ inputs.dockerfile }} diff --git a/workflows/_python.yml b/workflows/_python.yml index f8ae359..8e67133 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -412,12 +412,6 @@ jobs: shell: bash working-directory: ${{ inputs.check_docs_directory }} - - name: Build DockerFile - if: inputs.check_dockerfile - run: | - docker build -f ${{ inputs.check_dockerfile }} . - working-directory: ${{ inputs.working_directory }} - - name: Start services uses: ./.github/actions/services if: inputs.use_postgres || inputs.use_elastic_search || inputs.use_memcached || inputs.use_redis || inputs.use_rabbitmq || inputs.use_mongo diff --git a/workflows/_release_and_tag.yml b/workflows/_release_and_tag.yml index acc8181..e899456 100644 --- a/workflows/_release_and_tag.yml +++ b/workflows/_release_and_tag.yml @@ -31,11 +31,40 @@ on: required: false default: #CyberSecurity + publish_on_ecr: + description: Publish on ecr + type: boolean + required: false + default: false + repository: + description: Repository name + type: string + required: false + default: ${{ github.event.repository.name }} + + dockerfiles: + description: Path for dockerfiles from working directory + type: string + required: false + working_directory: + description: Docker build context + type: string + required: false + default: . + aws_region: + description: Aws region + type: string + required: false + default: eu-central-1 + + jobs: release_and_tag: name: Create release and tag runs-on: ubuntu-latest - if: github.event.pull_request.merged == true && ( github.base_ref == 'master' || github.base_ref == 'main' ) + if: github.event.pull_request.merged == true + outputs: + match: ${{ steps.check-tag.outputs.match }} steps: - uses: actions/checkout@v4 with: @@ -43,6 +72,7 @@ jobs: - name: Check Tag id: check-tag + if: github.base_ref == 'master' || github.base_ref == 'main' run: | if [[ "${{ github.event.pull_request.title }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "match=true" >> $GITHUB_OUTPUT @@ -115,4 +145,42 @@ jobs: api_key: ${{ secrets.TWITTER_API_KEY }} api_key_secret: ${{ secrets.TWITTER_API_KEY_SECRET }} access_token: ${{ secrets.TWITTER_ACCESS_TOKEN }} - access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} \ No newline at end of file + access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + + + push_on_ecr: + runs-on: ubuntu-latest + needs: release_and_tag + if: github.event.pull_request.merged == true && inputs.publish_on_ecr == true + strategy: + matrix: + dockerfile: ${{ fromJson(inputs.dockerfiles) }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # otherwise, you do not retrieve the tags + - name: Push on ecr branch + uses: ./.github/actions/push_on_ecr + if: github.base_ref == 'master' || github.base_ref == 'main' || github.base_ref == 'develop' || github.base_ref == 'dev' + with: + repository: ${{ inputs.repository }} + aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }} + aws_access_key: ${{ secrets.AWS_ACCESS_KEY}} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + dockerfile: ${{ matrix.dockerfile }} + image_tag: ${{ ( github.base_ref == 'main' || github.base_ref == 'master' ) && 'prod' || 'stag' }} + aws_region: ${{ inputs.aws_region }} + working_directory: ${{ inputs.working_directory }} + + - name: Push on ecr new release + if: needs.release_and_tag.outputs.match == 'true' && (github.base_ref == 'master' || github.base_ref == 'main' ) + uses: ./.github/actions/push_on_ecr + with: + repository: ${{ inputs.repository }} + aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }} + aws_access_key: ${{ secrets.AWS_ACCESS_KEY}} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + dockerfile: ${{ inputs.dockerfile }} + image_tag: ${{ github.event.pull_request.title }} + aws_region: ${{ inputs.aws_region }} + working_directory: ${{ inputs.working_directory }} \ No newline at end of file diff --git a/workflows/pull_request_automation.yml b/workflows/pull_request_automation.yml index 5ec92ee..7c3ffb4 100644 --- a/workflows/pull_request_automation.yml +++ b/workflows/pull_request_automation.yml @@ -72,7 +72,6 @@ jobs: check_migrations: true check_requirements_licenses: true check_docs_directory: - check_dockerfile: Dockerfile use_postgres: false postgres_db: db diff --git a/workflows/release.yml b/workflows/release.yml index 4987b88..7288a8c 100644 --- a/workflows/release.yml +++ b/workflows/release.yml @@ -20,3 +20,9 @@ jobs: publish_on_test_pypi: false publish_on_npm: false publish_on_twitter: false + publish_on_ecr: false + repository: certego-test + working_directory: .github/test/python_test + dockerfiles: >- + ["Dockerfile"] + aws_region: eu-central-1 From b6fd709437165ae76e47aa613e53c11d6e8763d7 Mon Sep 17 00:00:00 2001 From: eugenioseveri Date: Wed, 19 Mar 2025 12:05:13 +0100 Subject: [PATCH 07/15] Updated changelog --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c336b82..6e93115 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,13 @@ # 1.6.x ## 1.6.0 ### Features - +* Added "release.yml" action to to push containers to AWS ECR * Added *create_apt_cache.yaml* workflow to cache APT requirements each time a commit is pushed on selected branch and **when the requirements file has changed**. - +### Bugfix +* Updated python linters also in '_python.yml' workflow (missing from previous release) +* ### Changes - +* Deprecation of license check table-headers * Updated Python linters: * bandit 1.7.9 -> 1.8.3 * black 24.8.0 -> 25.1.0 From 548235bcc5bc40137ba8a969efbea77a3a10cf1e Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Tue, 25 Mar 2025 11:08:09 +0100 Subject: [PATCH 08/15] Linter requirements reconciliated (#215) * Linter requirements reconciliated * removed comments --- .github/workflows/_python.yml | 36 +++++++++++++++++++++++++++-------- CHANGELOG.md | 1 + workflows/_python.yml | 35 +++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index 8e67133..405a59f 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -292,39 +292,59 @@ jobs: exit 1 shell: bash + # TODO this comment is still relevant? # not the best solution because i do not think that dependabot supports this - name: Create requirements-linters.txt run: | + function check_linter_dependency_and_append_to_file { + # + # Function to check whether a specific linter is in the requirements file + # If it can be found inside the requirements, said linter dependency will be appended to a newly created requirements-linter.txt file. + # If the linter is not found inside the requirements file an error will be raised. + # + # 1st parameter: Name of the linter. + # 2nd parameter: Path of the requirements file. + # + if [[ -z $(grep -P "^$1[^a-zA-Z0-9_-].*" "$2") ]]; then + echo "::error::$1 dependency not found in $2 file!" + exit 1 + else + echo "$1 dependency found in $2!" + echo "$(grep -P ^$1[^a-zA-Z0-9_-].* $2)" >> requirements-linters.txt + fi + } + CI_REQUIREMENTS_LINTERS="${GITHUB_WORKSPACE}/.github/configurations/python_linters/requirements-linters.txt" echo > requirements-linters.txt if [[ '${{ inputs.use_black}}' != 'false' ]]; then - echo "black==24.8.0" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "black" "$CI_REQUIREMENTS_LINTERS" fi if [[ '${{ inputs.use_isort}}' != 'false' ]]; then - echo "isort==5.13.2" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "isort" "$CI_REQUIREMENTS_LINTERS" fi if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then - echo "flake8==7.1.1" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "flake8" "$CI_REQUIREMENTS_LINTERS" if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "flake8-django" "$CI_REQUIREMENTS_LINTERS" fi fi if [[ '${{ inputs.use_pylint}}' != 'false' ]]; then - echo "pylint==3.2.6" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "pylint" "$CI_REQUIREMENTS_LINTERS" if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "pylint-django==2.5.5" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "pylint-django" "$CI_REQUIREMENTS_LINTERS" fi fi if [[ '${{ inputs.use_bandit}}' != 'false' ]]; then - echo "bandit==1.7.9" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" fi if [[ '${{ inputs.use_autoflake}}' != 'false' ]]; then - echo "autoflake==2.3.1" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" fi + # TODO does this make any sense? It seems a copy paste of the same file cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-linter.txt/') >> requirements-linters.txt 2>/dev/null || exit 0 shell: bash working-directory: ${{ inputs.install_from }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e93115..77e5cac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,3 +19,4 @@ * Added both frontend and backend exclusions on _detect_changes.yaml (paths that won't be considered by git diff) * Updated CodeQL action v2 -> v3 (v2 has been [deprecated](https://github.blog/changelog/2024-01-12-code-scanning-deprecation-of-codeql-action-v2/) on december '24) * Removed `setup-python-dependencies` from `codeql/action.yml` since it has no effect anymore. See [this](https://github.blog/changelog/2024-01-23-codeql-2-16-python-dependency-installation-disabled-new-queries-and-bug-fixes/) for more information. +* Linters versions in step `Create requirements-linters.txt` of `_python.yml` action are now computed according to `configurations/python_linters/requirements-linters.txt`. As of now, linter updates are only required in `configurations/python_linters/requirements-linters.txt`. diff --git a/workflows/_python.yml b/workflows/_python.yml index 8e67133..04f71a0 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -292,38 +292,55 @@ jobs: exit 1 shell: bash - # not the best solution because i do not think that dependabot supports this - name: Create requirements-linters.txt run: | + function check_linter_dependency_and_append_to_file { + # + # Function to check whether a specific linter is in the requirements file + # If it can be found inside the requirements, said linter dependency will be appended to a newly created requirements-linter.txt file. + # If the linter is not found inside the requirements file an error will be raised. + # + # 1st parameter: Name of the linter. + # 2nd parameter: Path of the requirements file. + # + if [[ -z $(grep -P "^$1[^a-zA-Z0-9_-].*" "$2") ]]; then + echo "::error::$1 dependency not found in $2 file!" + exit 1 + else + echo "$1 dependency found in $2!" + echo "$(grep -P ^$1[^a-zA-Z0-9_-].* $2)" >> requirements-linters.txt + fi + } + CI_REQUIREMENTS_LINTERS="${GITHUB_WORKSPACE}/.github/configurations/python_linters/requirements-linters.txt" echo > requirements-linters.txt if [[ '${{ inputs.use_black}}' != 'false' ]]; then - echo "black==24.8.0" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "black" "$CI_REQUIREMENTS_LINTERS" fi if [[ '${{ inputs.use_isort}}' != 'false' ]]; then - echo "isort==5.13.2" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "isort" "$CI_REQUIREMENTS_LINTERS" fi if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then - echo "flake8==7.1.1" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "flake8" "$CI_REQUIREMENTS_LINTERS" if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "flake8-django" "$CI_REQUIREMENTS_LINTERS" fi fi if [[ '${{ inputs.use_pylint}}' != 'false' ]]; then - echo "pylint==3.2.6" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "pylint" "$CI_REQUIREMENTS_LINTERS" if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "pylint-django==2.5.5" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "pylint-django" "$CI_REQUIREMENTS_LINTERS" fi fi if [[ '${{ inputs.use_bandit}}' != 'false' ]]; then - echo "bandit==1.7.9" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" fi if [[ '${{ inputs.use_autoflake}}' != 'false' ]]; then - echo "autoflake==2.3.1" >> requirements-linters.txt + check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" fi cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-linter.txt/') >> requirements-linters.txt 2>/dev/null || exit 0 shell: bash From 013f31a6d9591fa3880d861928684db0499d4e12 Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Tue, 25 Mar 2025 11:34:52 +0100 Subject: [PATCH 09/15] Python caching revisited (#217) * Python caching revisited * renamed step in apt_requirements composite action * updated .github and review changelog --- .github/actions/apt_requirements/action.yml | 27 +-- .../misc/compute_files_hash/action.yml | 38 ++++ .../create_dev_requirements_file/action.yml | 28 +++ .../create_docs_requirements_file/action.yml | 37 ++++ .../action.yml | 87 +++++++++ .../create_virtualenv/action.yml | 26 +++ .../restore_pip_cache/action.yml | 52 +++++ .../restore_virtualenv/action.yml | 43 +++++ .../save_pip_cache/action.yml | 37 ++++ .../save_virtualenv/action.yml | 29 +++ .github/workflows/_python.yml | 178 ++++++++---------- .github/workflows/_release_and_tag.yml | 4 +- .github/workflows/create_apt_cache.yaml | 4 +- .github/workflows/pull_request_automation.yml | 2 +- CHANGELOG.md | 13 +- actions/apt_requirements/action.yml | 27 +-- actions/misc/compute_files_hash/action.yml | 38 ++++ .../create_dev_requirements_file/action.yml | 28 +++ .../create_docs_requirements_file/action.yml | 37 ++++ .../action.yml | 87 +++++++++ .../create_virtualenv/action.yml | 26 +++ .../restore_pip_cache/action.yml | 52 +++++ .../restore_virtualenv/action.yml | 43 +++++ .../save_pip_cache/action.yml | 37 ++++ .../save_virtualenv/action.yml | 29 +++ workflows/_python.yml | 175 ++++++++--------- workflows/create_apt_cache.yaml | 18 +- workflows/create_python_cache.yaml | 50 +++++ workflows/pull_request_automation.yml | 2 +- 29 files changed, 1017 insertions(+), 237 deletions(-) create mode 100644 .github/actions/misc/compute_files_hash/action.yml create mode 100644 .github/actions/python_requirements/create_dev_requirements_file/action.yml create mode 100644 .github/actions/python_requirements/create_docs_requirements_file/action.yml create mode 100644 .github/actions/python_requirements/create_linter_requirements_file/action.yml create mode 100644 .github/actions/python_requirements/create_virtualenv/action.yml create mode 100644 .github/actions/python_requirements/restore_pip_cache/action.yml create mode 100644 .github/actions/python_requirements/restore_virtualenv/action.yml create mode 100644 .github/actions/python_requirements/save_pip_cache/action.yml create mode 100644 .github/actions/python_requirements/save_virtualenv/action.yml create mode 100644 actions/misc/compute_files_hash/action.yml create mode 100644 actions/python_requirements/create_dev_requirements_file/action.yml create mode 100644 actions/python_requirements/create_docs_requirements_file/action.yml create mode 100644 actions/python_requirements/create_linter_requirements_file/action.yml create mode 100644 actions/python_requirements/create_virtualenv/action.yml create mode 100644 actions/python_requirements/restore_pip_cache/action.yml create mode 100644 actions/python_requirements/restore_virtualenv/action.yml create mode 100644 actions/python_requirements/save_pip_cache/action.yml create mode 100644 actions/python_requirements/save_virtualenv/action.yml create mode 100644 workflows/create_python_cache.yaml diff --git a/.github/actions/apt_requirements/action.yml b/.github/actions/apt_requirements/action.yml index 0024e2c..7134837 100644 --- a/.github/actions/apt_requirements/action.yml +++ b/.github/actions/apt_requirements/action.yml @@ -1,5 +1,5 @@ -name: Composite action install apt requirements -description: Composite action install apt requirements +name: Composite action install APT requirements +description: Composite action to install APT requirements inputs: requirements_file: description: Requirements file @@ -8,12 +8,11 @@ inputs: runs: using: "composite" steps: - - name: Compute APT requirements file SHA256 hash + - name: Compute apt requirements file SHA256 hash id: compute_apt_requirements_file_sha256_hash - run: | - COMPUTED_HASH=$(sha256sum ${{ inputs.requirements_file }} | cut -d ' ' -f 1) - echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT - shell: bash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.requirements_file }} # Vital to be able to restore cache # If write permission is not set, a permissions error will be raised @@ -26,17 +25,19 @@ runs: id: restore_cache_from_parent_branch with: path: /var/cache/apt/archives/*.deb - key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - uses: actions/cache/restore@v4 id: restore_cache_from_current_branch if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' with: path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - name: Refresh repositories - if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' + if: > + steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && + steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' run: | sudo apt-get update shell: bash @@ -48,7 +49,9 @@ runs: - uses: actions/cache/save@v4 id: cache_apt_requirements_for_current_branch - if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' + if: > + steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && + steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' with: path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} \ No newline at end of file + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/.github/actions/misc/compute_files_hash/action.yml b/.github/actions/misc/compute_files_hash/action.yml new file mode 100644 index 0000000..2c3b905 --- /dev/null +++ b/.github/actions/misc/compute_files_hash/action.yml @@ -0,0 +1,38 @@ +name: Composite action compute files hash +description: Composite action to compute a single hash of one or more files +inputs: + file_paths: + description: Comma separeted list of files. + required: false + +outputs: + computed_hash: + description: The hash of the concatenated files + value: ${{ steps.compute_files_sha256_hash.outputs.computed_hash }} + +runs: + using: "composite" + steps: + - name: Compute files SHA256 hash + id: compute_files_sha256_hash + run: | + JOINED_FILES="cat " + # Create a bash array of file paths + IFS=',' read -r -a files <<< "${{ inputs.file_paths }}" + echo "::debug::File paths array is composed by: ${files[@]}" + for file in ${files[@]}; + do + if [[ -f $file ]]; then + # Concat file path to cat command + JOINED_FILES+="$file " + echo "::debug::Current file is $file" + echo "::debug::JOINED_FILES variable state is $JOINED_FILES" + else + echo "::error::$file does not exist or it is not a regular file!" + exit 1 + fi + done + COMPUTED_HASH=$($JOINED_FILES | sha256sum | cut -d ' ' -f 1) + echo "::debug::Hash is $COMPUTED_HASH" + echo "computed_hash=$COMPUTED_HASH" >> $GITHUB_OUTPUT + shell: bash \ No newline at end of file diff --git a/.github/actions/python_requirements/create_dev_requirements_file/action.yml b/.github/actions/python_requirements/create_dev_requirements_file/action.yml new file mode 100644 index 0000000..eb86a04 --- /dev/null +++ b/.github/actions/python_requirements/create_dev_requirements_file/action.yml @@ -0,0 +1,28 @@ +name: Composite action create Python dev requirements file +description: Composite action to create Python dev requirements file +inputs: + install_from: + description: Directory that must be used to install the packages + required: false + default: . + project_dev_requirements_file: + description: An additional project dev requirements file + required: false + use_coverage: + description: Use coverage.py + required: false + +runs: + using: "composite" + steps: + - name: Create requirements-dev.txt + run: | + echo > requirements-dev.txt + if [[ '${{ inputs.use_coverage }}' != 'false' ]]; then + echo "coverage>=7.3.2" >> requirements-dev.txt + fi + if [[ -z '${{ inputs.project_dev_requirements_file }}' ]];then + cat $(echo ${{ inputs.project_dev_requirements_file }}) >> requirements-dev.txt + fi + shell: bash + working-directory: ${{ inputs.install_from }} \ No newline at end of file diff --git a/.github/actions/python_requirements/create_docs_requirements_file/action.yml b/.github/actions/python_requirements/create_docs_requirements_file/action.yml new file mode 100644 index 0000000..fb674f8 --- /dev/null +++ b/.github/actions/python_requirements/create_docs_requirements_file/action.yml @@ -0,0 +1,37 @@ +name: Composite action create Python docs requirements file +description: Composite action to create Python docs requirements file +inputs: + install_from: + description: Directory that must be used to install the packages + required: false + default: . + project_docs_requirements_file: + description: An additional project docs requirements file + required: false + django_settings_module: + description: Path to the django settings file + required: false + check_docs_directory: + description: Check docs using rstcheck inside this directory + required: false + +runs: + using: "composite" + steps: + - name: Create requirements-docs.txt + run: | + echo > requirements-docs.txt + if [[ -n '${{ inputs.check_docs_directory }}' ]]; then + echo "rstcheck[sphinx]" >> requirements-docs.txt + echo "sphinx==7.2.6" >> requirements-docs.txt + echo "sphinx_rtd_theme==1.3.0" >> requirements-docs.txt + echo "sphinxcontrib-spelling==8.0.0" >> requirements-docs.txt + if [[ -n '${{ inputs.django_settings_module }}' ]]; then + echo "sphinxcontrib-django2==1.9" >> requirements-docs.txt + fi + if [[ -z '${{ inputs.project_docs_requirements_file }}' ]];then + cat $(echo ${{ inputs.project_docs_requirements_file }}) >> requirements-docs.txt + fi + fi + shell: bash + working-directory: ${{ inputs.install_from }} \ No newline at end of file diff --git a/.github/actions/python_requirements/create_linter_requirements_file/action.yml b/.github/actions/python_requirements/create_linter_requirements_file/action.yml new file mode 100644 index 0000000..7edb47f --- /dev/null +++ b/.github/actions/python_requirements/create_linter_requirements_file/action.yml @@ -0,0 +1,87 @@ +name: Composite action create Python linter requirements file +description: Composite action to create Python linter requirements file +inputs: + install_from: + description: Directory that must be used to install the packages + required: false + default: . + project_linter_requirements_file: + description: An additional project linter requirements file + required: false + django_settings_module: + description: Path to the django settings file + required: false + use_autoflake: + description: Use autoflake linter + required: false + use_bandit: + description: Use bandit linter + required: false + use_flake8: + description: Use flake8 linter + required: false + use_pylint: + description: Use pylint linter + required: false + + + +runs: + using: "composite" + steps: + - name: Create requirements-linters.txt + run: | + function check_linter_dependency_and_append_to_file { + # + # Function to check whether a specific linter is in the requirements file + # If it can be found inside the requirements, said linter dependency will be appended to a newly created requirements-linter.txt file. + # If the linter is not found inside the requirements file an error will be raised. + # + # 1st parameter: Name of the linter. + # 2nd parameter: Path of the requirements file. + # + if [[ -z $(grep -P "^$1[^a-zA-Z0-9_-].*" "$2") ]]; then + echo "::error::$1 dependency not found in $2 file!" + exit 1 + else + echo "$1 dependency found in $2!" + echo "$(grep -P ^$1[^a-zA-Z0-9_-].* $2)" >> requirements-linters.txt + fi + } + CI_REQUIREMENTS_LINTERS="${GITHUB_WORKSPACE}/.github/configurations/python_linters/requirements-linters.txt" + echo > requirements-linters.txt + + if [[ '${{ inputs.use_black }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "black" "$CI_REQUIREMENTS_LINTERS" + fi + + if [[ '${{ inputs.use_isort }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "isort" "$CI_REQUIREMENTS_LINTERS" + fi + + if [[ '${{ inputs.use_flake8 }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "flake8" "$CI_REQUIREMENTS_LINTERS" + if [[ -n '${{ inputs.django_settings_module }}' ]]; then + check_linter_dependency_and_append_to_file "flake8-django" "$CI_REQUIREMENTS_LINTERS" + fi + fi + + if [[ '${{ inputs.use_pylint }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "pylint" "$CI_REQUIREMENTS_LINTERS" + if [[ -n '${{ inputs.django_settings_module }}' ]]; then + check_linter_dependency_and_append_to_file "pylint-django" "$CI_REQUIREMENTS_LINTERS" + fi + fi + + if [[ '${{ inputs.use_bandit }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" + fi + if [[ '${{ inputs.use_autoflake }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" + fi + + if [[ -z '${{ inputs.project_linter_requirements_file }}' ]]; then + cat $(echo ${{ inputs.project_linter_requirements_file }}) >> requirements-linters.txt + fi + shell: bash + working-directory: ${{ inputs.install_from }} \ No newline at end of file diff --git a/.github/actions/python_requirements/create_virtualenv/action.yml b/.github/actions/python_requirements/create_virtualenv/action.yml new file mode 100644 index 0000000..00a40a4 --- /dev/null +++ b/.github/actions/python_requirements/create_virtualenv/action.yml @@ -0,0 +1,26 @@ +name: Composite action create Python virtual environment +description: Composite action create Python virtual environment +inputs: + virtualenv_path: + description: Python's virtual environment path. + required: false + default: ".venv" + activate_only: + description: Whether to create the virtual environment or only activate it. + required: false + default: false + +runs: + using: "composite" + steps: + - name: Python's virtualenv creation + if: inputs.activate_only != 'true' + run: python -m venv ${{ inputs.virtualenv_path }} + shell: bash + - name: Activate newly created virtualenv + id: activate_newly_created_virtualenv + run: | + source ${{ inputs.virtualenv_path }}/bin/activate + echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV + echo "$VIRTUAL_ENV/bin" >> $GITHUB_PATH + shell: bash diff --git a/.github/actions/python_requirements/restore_pip_cache/action.yml b/.github/actions/python_requirements/restore_pip_cache/action.yml new file mode 100644 index 0000000..0c4f93b --- /dev/null +++ b/.github/actions/python_requirements/restore_pip_cache/action.yml @@ -0,0 +1,52 @@ +name: Composite action restore pip's cache +description: Composite action to restore pip's cache +inputs: + custom_pip_cache_path: + description: Path to pip cache. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +outputs: + cache-hit: + description: Whether pip cache was found in the cache or not. + value: ${{ steps.explain_cache_output.outputs.real_cache_hit }} + +runs: + using: "composite" + steps: + - name: Generate random UUID + id: generate_random_uuid + run: | + random_uuid=$(uuidgen -r) + echo "::debug::Random uuid generated is $random_uuid. Should only cause a cache-miss" + echo "computed_uuid=$random_uuid" >> $GITHUB_OUTPUT + shell: bash + - name: Get pip cache directory + id: get_pip_cache_directory + run: | + if [[ -z '${{ inputs.custom_pip_cache_path }}' ]]; then + echo "pip_cache_path=$(pip cache dir)" >> $GITHUB_OUTPUT + else + echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT + fi + shell: bash + - name: Restore pip cache + id: restore_pip_cache + uses: actions/cache/restore@v4 + with: + key: ${{ steps.generate_random_uuid.outputs.computed_uuid }} + path: ${{ steps.get_pip_cache_directory.outputs.pip_cache_path }} + restore-keys: ${{ inputs.git_reference }}-pip-cache- + - name: Explain cache output + id: explain_cache_output + run: | + echo "::debug::Restore action for pip's cache returned cache-hit: ${{ steps.restore_pip_cache.outputs.cache-hit }} with cache-matched-key: ${{ steps.restore_pip_cache.outputs.cache-matched-key }}" + if [[ -z '${{ steps.restore_pip_cache.outputs.cache-matched-key }}' ]]; then + echo "real_cache_hit=false" >> $GITHUB_OUTPUT + else + echo "real_cache_hit=true" >> $GITHUB_OUTPUT + fi + shell: bash \ No newline at end of file diff --git a/.github/actions/python_requirements/restore_virtualenv/action.yml b/.github/actions/python_requirements/restore_virtualenv/action.yml new file mode 100644 index 0000000..1798a87 --- /dev/null +++ b/.github/actions/python_requirements/restore_virtualenv/action.yml @@ -0,0 +1,43 @@ +name: Composite action restore Python virtual environment +description: Composite action to restore Python virtual environment +inputs: + virtual_environment_path: + description: Path to where virtual environment will be restored. + required: false + default: ".venv" + requirements_paths: + description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +outputs: + cache-hit: + description: Whether virtual environment was found in the cache or not. + value: ${{ steps.restore_virtual_environment.outputs.cache-hit }} + +runs: + using: "composite" + steps: + - name: Compute requirements files SHA256 hash + id: compute_requirements_files_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.requirements_paths }} + + - name: Restore virtual environment + id: restore_virtual_environment + uses: actions/cache/restore@v4 + with: + path: ${{ inputs.virtual_environment_path }} + key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} + + - name: Activate restored virtual environment + if: > + steps.restore_virtual_environment.outputs.cache-hit == 'true' + uses: ./.github/actions/python_requirements/create_virtualenv + with: + virtualenv_path: ${{ inputs.virtual_environment_path }} + activate_only: true \ No newline at end of file diff --git a/.github/actions/python_requirements/save_pip_cache/action.yml b/.github/actions/python_requirements/save_pip_cache/action.yml new file mode 100644 index 0000000..218e508 --- /dev/null +++ b/.github/actions/python_requirements/save_pip_cache/action.yml @@ -0,0 +1,37 @@ +name: Composite action save pip's cache +description: Composite action to save pip's cache +inputs: + custom_pip_cache_path: + description: Path to pip cache. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +runs: + using: "composite" + steps: + # TODO non posso usare l'hash del file perchè quando vado ad aggiornare i requirements + # l'hash cambia e sicuramente non trovo la cache salvata + - name: Generate random UUID + id: generate_random_uuid + run: | + random_uuid=$(uuidgen -r) + echo "::debug::Random uuid generated is $random_uuid" + echo "computed_uuid=$random_uuid" >> $GITHUB_OUTPUT + shell: bash + - name: Get pip cache directory + id: get_pip_cache_directory + run: | + if [[ -z '${{ inputs.custom_pip_cache_path }}' ]]; then + echo "pip_cache_path=$(pip cache dir)" >> $GITHUB_OUTPUT + else + echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT + fi + shell: bash + - name: Save pip cache + uses: actions/cache/save@v4 + with: + path: ${{ steps.get_pip_cache_directory.outputs.pip_cache_path }} + key: ${{ inputs.git_reference }}-pip-cache-${{ steps.generate_random_uuid.outputs.computed_uuid }} \ No newline at end of file diff --git a/.github/actions/python_requirements/save_virtualenv/action.yml b/.github/actions/python_requirements/save_virtualenv/action.yml new file mode 100644 index 0000000..b93d66c --- /dev/null +++ b/.github/actions/python_requirements/save_virtualenv/action.yml @@ -0,0 +1,29 @@ +name: Composite action save Python virtual environment +description: Composite action to save Python virtual environment +inputs: + virtual_environment_path: + description: Path to virtual environment. + required: false + default: ".venv" + requirements_paths: + description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +runs: + using: "composite" + steps: + - name: Compute requirements files SHA256 hash + id: compute_requirements_files_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.requirements_paths }} + + - name: Cache virtual environment + uses: actions/cache/save@v4 + with: + path: ${{ inputs.virtual_environment_path }} + key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index 405a59f..1f6624f 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -248,7 +248,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python_version }} @@ -292,119 +292,97 @@ jobs: exit 1 shell: bash - # TODO this comment is still relevant? - # not the best solution because i do not think that dependabot supports this - - name: Create requirements-linters.txt - run: | - function check_linter_dependency_and_append_to_file { - # - # Function to check whether a specific linter is in the requirements file - # If it can be found inside the requirements, said linter dependency will be appended to a newly created requirements-linter.txt file. - # If the linter is not found inside the requirements file an error will be raised. - # - # 1st parameter: Name of the linter. - # 2nd parameter: Path of the requirements file. - # - if [[ -z $(grep -P "^$1[^a-zA-Z0-9_-].*" "$2") ]]; then - echo "::error::$1 dependency not found in $2 file!" - exit 1 - else - echo "$1 dependency found in $2!" - echo "$(grep -P ^$1[^a-zA-Z0-9_-].* $2)" >> requirements-linters.txt - fi - } - CI_REQUIREMENTS_LINTERS="${GITHUB_WORKSPACE}/.github/configurations/python_linters/requirements-linters.txt" - echo > requirements-linters.txt - - if [[ '${{ inputs.use_black}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "black" "$CI_REQUIREMENTS_LINTERS" - fi - - if [[ '${{ inputs.use_isort}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "isort" "$CI_REQUIREMENTS_LINTERS" - fi - - if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "flake8" "$CI_REQUIREMENTS_LINTERS" - if [[ -n '${{ inputs.django_settings_module }}' ]]; then - check_linter_dependency_and_append_to_file "flake8-django" "$CI_REQUIREMENTS_LINTERS" - fi - fi + - name: Create linter requirements file + uses: ./.github/actions/python_requirements/create_linter_requirements_file + with: + install_from: ${{ inputs.install_from }} + django_settings_module: ${{ inputs.django_settings_module }} + use_autoflake: ${{ inputs.use_autoflake }} + use_bandit: ${{ inputs.use_bandit }} + use_flake8: ${{ inputs.use_flake8 }} + use_pylint: ${{ inputs.use_pylint }} - if [[ '${{ inputs.use_pylint}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "pylint" "$CI_REQUIREMENTS_LINTERS" - if [[ -n '${{ inputs.django_settings_module }}' ]]; then - check_linter_dependency_and_append_to_file "pylint-django" "$CI_REQUIREMENTS_LINTERS" - fi - fi + - name: Create dev requirements file + uses: ./.github/actions/python_requirements/create_dev_requirements_file + with: + install_from: ${{ inputs.install_from }} + use_coverage: ${{ inputs.use_coverage }} - if [[ '${{ inputs.use_bandit}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" - fi - if [[ '${{ inputs.use_autoflake}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" - fi - # TODO does this make any sense? It seems a copy paste of the same file - cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-linter.txt/') >> requirements-linters.txt 2>/dev/null || exit 0 - shell: bash - working-directory: ${{ inputs.install_from }} + - name: Create docs requirements file + uses: ./.github/actions/python_requirements/create_docs_requirements_file + with: + install_from: ${{ inputs.install_from }} + check_docs_directory: ${{ inputs.check_docs_directory }} + django_settings_module: ${{ inputs.django_settings_module }} - - name: Create requirements-dev.txt - run: | - echo > requirements-dev.txt - if [[ '${{ inputs.use_coverage }}' != 'false' ]]; then - echo "coverage>=7.3.2" >> requirements-dev.txt - fi - cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-dev.txt/') >> requirements-dev.txt 2>/dev/null || exit 0 - shell: bash - working-directory: ${{ inputs.install_from }} + - name: Restore Python virtual environment related to PR event + id: restore_python_virtual_environment_pr + uses: ./.github/actions/python_requirements/restore_virtualenv/ + with: + requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" - - name: Create requirements-docs.txt - run: | - echo > requirements-docs.txt - if [[ -n '${{ inputs.check_docs_directory }}' ]]; then - echo "rstcheck[sphinx]" >> requirements-docs.txt - echo "sphinx==7.2.6" >> requirements-docs.txt - echo "sphinx_rtd_theme==1.3.0" >> requirements-docs.txt - echo "sphinxcontrib-spelling==8.0.0" >> requirements-docs.txt - if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "sphinxcontrib-django2==1.9" >> requirements-docs.txt - fi - cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-docs.txt/') >> requirements-docs.txt 2>/dev/null || exit 0 - fi + - name: Restore Python virtual environment related to target branch + id: restore_python_virtual_environment_target_branch + if: steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/restore_virtualenv/ + with: + requirements_paths: ${{ inputs.requirements_path }} + git_reference: ${{ github.base_ref }} + + - name: Create Python virtual environment + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/create_virtualenv + + - name: Restore pip cache related to PR event + id: restore_pip_cache_pr + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/restore_pip_cache + + - name: Restore pip cache related to target branch + id: restore_pip_cache_target_branch + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' && + steps.restore_pip_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/restore_pip_cache + with: + git_reference: ${{ github.base_ref }} + + - name: Install project requirements + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' + run: pip install -r ${{ inputs.requirements_path }} shell: bash working-directory: ${{ inputs.install_from }} - - name: Check virtualenv cache - uses: syphar/restore-virtualenv@v1 - id: cache-virtualenv - with: - requirement_files: | - ${{ inputs.install_from }}/${{ inputs.requirements_path }} - ${{ inputs.install_from }}/requirements-dev.txt - ${{ inputs.install_from }}/requirements-linters.txt - ${{ inputs.install_from }}/requirements-docs.txt - - - name: Check pip cache - uses: syphar/restore-pip-download-cache@v1 - if: steps.cache-virtualenv.outputs.cache-hit != 'true' - with: - requirement_files: | - ${{ inputs.install_from }}/${{ inputs.requirements_path }} - ${{ inputs.install_from }}/requirements-dev.txt - ${{ inputs.install_from }}/requirements-linters.txt - ${{ inputs.install_from }}/requirements-docs.txt - - - name: Install requirements - if: steps.cache-virtualenv.outputs.cache-hit != 'true' + - name: Install other requirements + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' run: | - pip install -r ${{ inputs.requirements_path }} pip install -r requirements-dev.txt pip install -r requirements-linters.txt pip install -r requirements-docs.txt shell: bash working-directory: ${{ inputs.install_from }} + - name: Save Python virtual environment related to the PR event + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/save_virtualenv + with: + requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" + + - name: Save pip cache related to the PR event + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_pip_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/save_pip_cache + - name: Run linters uses: ./.github/actions/python_linter if: inputs.use_black || inputs.use_isort || inputs.use_flake8 || inputs.use_pylint || inputs.use_bandit || inputs.use_autoflake diff --git a/.github/workflows/_release_and_tag.yml b/.github/workflows/_release_and_tag.yml index aaa5124..e899456 100644 --- a/.github/workflows/_release_and_tag.yml +++ b/.github/workflows/_release_and_tag.yml @@ -161,14 +161,14 @@ jobs: fetch-depth: 0 # otherwise, you do not retrieve the tags - name: Push on ecr branch uses: ./.github/actions/push_on_ecr - if: github.base_ref == 'master' || github.base_ref == 'main' || github.base_ref == 'develop' || github.base_ref == 'dev' || github.base_ref == 'test' + if: github.base_ref == 'master' || github.base_ref == 'main' || github.base_ref == 'develop' || github.base_ref == 'dev' with: repository: ${{ inputs.repository }} aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }} aws_access_key: ${{ secrets.AWS_ACCESS_KEY}} aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} dockerfile: ${{ matrix.dockerfile }} - image_tag: ${{ ( github.base_ref == 'main' || github.base_ref == 'master' ) && 'prod' || ( github.base_ref == 'develop' || github.base_ref == 'dev' ) && 'stag' || 'test' }} + image_tag: ${{ ( github.base_ref == 'main' || github.base_ref == 'master' ) && 'prod' || 'stag' }} aws_region: ${{ inputs.aws_region }} working_directory: ${{ inputs.working_directory }} diff --git a/.github/workflows/create_apt_cache.yaml b/.github/workflows/create_apt_cache.yaml index 2315fc9..7cd6937 100644 --- a/.github/workflows/create_apt_cache.yaml +++ b/.github/workflows/create_apt_cache.yaml @@ -16,13 +16,13 @@ on: jobs: create-cache: - name: Create cache for dependencies + name: Create cache for APT dependencies runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Remember to set the same APT requirements file path set before! - - name: Install dependencies + - name: Install APT dependencies run: | sudo apt-get update sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < apt_packages.txt) diff --git a/.github/workflows/pull_request_automation.yml b/.github/workflows/pull_request_automation.yml index 7c3ffb4..71deca6 100644 --- a/.github/workflows/pull_request_automation.yml +++ b/.github/workflows/pull_request_automation.yml @@ -101,6 +101,6 @@ jobs: env: >- {"KEY": "VALUE"} python_versions: >- - ["3.10"] + ["3.12"] max_timeout: 15 ubuntu_version: latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 77e5cac..aa1d0af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,18 @@ -# 1.6.x -## 1.6.0 +# 2.0.x + +## 2.0.0 + ### Features + * Added "release.yml" action to to push containers to AWS ECR * Added *create_apt_cache.yaml* workflow to cache APT requirements each time a commit is pushed on selected branch and **when the requirements file has changed**. + ### Bugfix + * Updated python linters also in '_python.yml' workflow (missing from previous release) -* + ### Changes + * Deprecation of license check table-headers * Updated Python linters: * bandit 1.7.9 -> 1.8.3 @@ -20,3 +26,4 @@ * Updated CodeQL action v2 -> v3 (v2 has been [deprecated](https://github.blog/changelog/2024-01-12-code-scanning-deprecation-of-codeql-action-v2/) on december '24) * Removed `setup-python-dependencies` from `codeql/action.yml` since it has no effect anymore. See [this](https://github.blog/changelog/2024-01-23-codeql-2-16-python-dependency-installation-disabled-new-queries-and-bug-fixes/) for more information. * Linters versions in step `Create requirements-linters.txt` of `_python.yml` action are now computed according to `configurations/python_linters/requirements-linters.txt`. As of now, linter updates are only required in `configurations/python_linters/requirements-linters.txt`. +* Reworked Python requirements caching. diff --git a/actions/apt_requirements/action.yml b/actions/apt_requirements/action.yml index 0024e2c..7134837 100644 --- a/actions/apt_requirements/action.yml +++ b/actions/apt_requirements/action.yml @@ -1,5 +1,5 @@ -name: Composite action install apt requirements -description: Composite action install apt requirements +name: Composite action install APT requirements +description: Composite action to install APT requirements inputs: requirements_file: description: Requirements file @@ -8,12 +8,11 @@ inputs: runs: using: "composite" steps: - - name: Compute APT requirements file SHA256 hash + - name: Compute apt requirements file SHA256 hash id: compute_apt_requirements_file_sha256_hash - run: | - COMPUTED_HASH=$(sha256sum ${{ inputs.requirements_file }} | cut -d ' ' -f 1) - echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT - shell: bash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.requirements_file }} # Vital to be able to restore cache # If write permission is not set, a permissions error will be raised @@ -26,17 +25,19 @@ runs: id: restore_cache_from_parent_branch with: path: /var/cache/apt/archives/*.deb - key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - uses: actions/cache/restore@v4 id: restore_cache_from_current_branch if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' with: path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - name: Refresh repositories - if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' + if: > + steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && + steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' run: | sudo apt-get update shell: bash @@ -48,7 +49,9 @@ runs: - uses: actions/cache/save@v4 id: cache_apt_requirements_for_current_branch - if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' + if: > + steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && + steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' with: path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.cache_key }} \ No newline at end of file + key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/actions/misc/compute_files_hash/action.yml b/actions/misc/compute_files_hash/action.yml new file mode 100644 index 0000000..2c3b905 --- /dev/null +++ b/actions/misc/compute_files_hash/action.yml @@ -0,0 +1,38 @@ +name: Composite action compute files hash +description: Composite action to compute a single hash of one or more files +inputs: + file_paths: + description: Comma separeted list of files. + required: false + +outputs: + computed_hash: + description: The hash of the concatenated files + value: ${{ steps.compute_files_sha256_hash.outputs.computed_hash }} + +runs: + using: "composite" + steps: + - name: Compute files SHA256 hash + id: compute_files_sha256_hash + run: | + JOINED_FILES="cat " + # Create a bash array of file paths + IFS=',' read -r -a files <<< "${{ inputs.file_paths }}" + echo "::debug::File paths array is composed by: ${files[@]}" + for file in ${files[@]}; + do + if [[ -f $file ]]; then + # Concat file path to cat command + JOINED_FILES+="$file " + echo "::debug::Current file is $file" + echo "::debug::JOINED_FILES variable state is $JOINED_FILES" + else + echo "::error::$file does not exist or it is not a regular file!" + exit 1 + fi + done + COMPUTED_HASH=$($JOINED_FILES | sha256sum | cut -d ' ' -f 1) + echo "::debug::Hash is $COMPUTED_HASH" + echo "computed_hash=$COMPUTED_HASH" >> $GITHUB_OUTPUT + shell: bash \ No newline at end of file diff --git a/actions/python_requirements/create_dev_requirements_file/action.yml b/actions/python_requirements/create_dev_requirements_file/action.yml new file mode 100644 index 0000000..eb86a04 --- /dev/null +++ b/actions/python_requirements/create_dev_requirements_file/action.yml @@ -0,0 +1,28 @@ +name: Composite action create Python dev requirements file +description: Composite action to create Python dev requirements file +inputs: + install_from: + description: Directory that must be used to install the packages + required: false + default: . + project_dev_requirements_file: + description: An additional project dev requirements file + required: false + use_coverage: + description: Use coverage.py + required: false + +runs: + using: "composite" + steps: + - name: Create requirements-dev.txt + run: | + echo > requirements-dev.txt + if [[ '${{ inputs.use_coverage }}' != 'false' ]]; then + echo "coverage>=7.3.2" >> requirements-dev.txt + fi + if [[ -z '${{ inputs.project_dev_requirements_file }}' ]];then + cat $(echo ${{ inputs.project_dev_requirements_file }}) >> requirements-dev.txt + fi + shell: bash + working-directory: ${{ inputs.install_from }} \ No newline at end of file diff --git a/actions/python_requirements/create_docs_requirements_file/action.yml b/actions/python_requirements/create_docs_requirements_file/action.yml new file mode 100644 index 0000000..fb674f8 --- /dev/null +++ b/actions/python_requirements/create_docs_requirements_file/action.yml @@ -0,0 +1,37 @@ +name: Composite action create Python docs requirements file +description: Composite action to create Python docs requirements file +inputs: + install_from: + description: Directory that must be used to install the packages + required: false + default: . + project_docs_requirements_file: + description: An additional project docs requirements file + required: false + django_settings_module: + description: Path to the django settings file + required: false + check_docs_directory: + description: Check docs using rstcheck inside this directory + required: false + +runs: + using: "composite" + steps: + - name: Create requirements-docs.txt + run: | + echo > requirements-docs.txt + if [[ -n '${{ inputs.check_docs_directory }}' ]]; then + echo "rstcheck[sphinx]" >> requirements-docs.txt + echo "sphinx==7.2.6" >> requirements-docs.txt + echo "sphinx_rtd_theme==1.3.0" >> requirements-docs.txt + echo "sphinxcontrib-spelling==8.0.0" >> requirements-docs.txt + if [[ -n '${{ inputs.django_settings_module }}' ]]; then + echo "sphinxcontrib-django2==1.9" >> requirements-docs.txt + fi + if [[ -z '${{ inputs.project_docs_requirements_file }}' ]];then + cat $(echo ${{ inputs.project_docs_requirements_file }}) >> requirements-docs.txt + fi + fi + shell: bash + working-directory: ${{ inputs.install_from }} \ No newline at end of file diff --git a/actions/python_requirements/create_linter_requirements_file/action.yml b/actions/python_requirements/create_linter_requirements_file/action.yml new file mode 100644 index 0000000..7edb47f --- /dev/null +++ b/actions/python_requirements/create_linter_requirements_file/action.yml @@ -0,0 +1,87 @@ +name: Composite action create Python linter requirements file +description: Composite action to create Python linter requirements file +inputs: + install_from: + description: Directory that must be used to install the packages + required: false + default: . + project_linter_requirements_file: + description: An additional project linter requirements file + required: false + django_settings_module: + description: Path to the django settings file + required: false + use_autoflake: + description: Use autoflake linter + required: false + use_bandit: + description: Use bandit linter + required: false + use_flake8: + description: Use flake8 linter + required: false + use_pylint: + description: Use pylint linter + required: false + + + +runs: + using: "composite" + steps: + - name: Create requirements-linters.txt + run: | + function check_linter_dependency_and_append_to_file { + # + # Function to check whether a specific linter is in the requirements file + # If it can be found inside the requirements, said linter dependency will be appended to a newly created requirements-linter.txt file. + # If the linter is not found inside the requirements file an error will be raised. + # + # 1st parameter: Name of the linter. + # 2nd parameter: Path of the requirements file. + # + if [[ -z $(grep -P "^$1[^a-zA-Z0-9_-].*" "$2") ]]; then + echo "::error::$1 dependency not found in $2 file!" + exit 1 + else + echo "$1 dependency found in $2!" + echo "$(grep -P ^$1[^a-zA-Z0-9_-].* $2)" >> requirements-linters.txt + fi + } + CI_REQUIREMENTS_LINTERS="${GITHUB_WORKSPACE}/.github/configurations/python_linters/requirements-linters.txt" + echo > requirements-linters.txt + + if [[ '${{ inputs.use_black }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "black" "$CI_REQUIREMENTS_LINTERS" + fi + + if [[ '${{ inputs.use_isort }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "isort" "$CI_REQUIREMENTS_LINTERS" + fi + + if [[ '${{ inputs.use_flake8 }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "flake8" "$CI_REQUIREMENTS_LINTERS" + if [[ -n '${{ inputs.django_settings_module }}' ]]; then + check_linter_dependency_and_append_to_file "flake8-django" "$CI_REQUIREMENTS_LINTERS" + fi + fi + + if [[ '${{ inputs.use_pylint }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "pylint" "$CI_REQUIREMENTS_LINTERS" + if [[ -n '${{ inputs.django_settings_module }}' ]]; then + check_linter_dependency_and_append_to_file "pylint-django" "$CI_REQUIREMENTS_LINTERS" + fi + fi + + if [[ '${{ inputs.use_bandit }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" + fi + if [[ '${{ inputs.use_autoflake }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" + fi + + if [[ -z '${{ inputs.project_linter_requirements_file }}' ]]; then + cat $(echo ${{ inputs.project_linter_requirements_file }}) >> requirements-linters.txt + fi + shell: bash + working-directory: ${{ inputs.install_from }} \ No newline at end of file diff --git a/actions/python_requirements/create_virtualenv/action.yml b/actions/python_requirements/create_virtualenv/action.yml new file mode 100644 index 0000000..00a40a4 --- /dev/null +++ b/actions/python_requirements/create_virtualenv/action.yml @@ -0,0 +1,26 @@ +name: Composite action create Python virtual environment +description: Composite action create Python virtual environment +inputs: + virtualenv_path: + description: Python's virtual environment path. + required: false + default: ".venv" + activate_only: + description: Whether to create the virtual environment or only activate it. + required: false + default: false + +runs: + using: "composite" + steps: + - name: Python's virtualenv creation + if: inputs.activate_only != 'true' + run: python -m venv ${{ inputs.virtualenv_path }} + shell: bash + - name: Activate newly created virtualenv + id: activate_newly_created_virtualenv + run: | + source ${{ inputs.virtualenv_path }}/bin/activate + echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV + echo "$VIRTUAL_ENV/bin" >> $GITHUB_PATH + shell: bash diff --git a/actions/python_requirements/restore_pip_cache/action.yml b/actions/python_requirements/restore_pip_cache/action.yml new file mode 100644 index 0000000..0c4f93b --- /dev/null +++ b/actions/python_requirements/restore_pip_cache/action.yml @@ -0,0 +1,52 @@ +name: Composite action restore pip's cache +description: Composite action to restore pip's cache +inputs: + custom_pip_cache_path: + description: Path to pip cache. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +outputs: + cache-hit: + description: Whether pip cache was found in the cache or not. + value: ${{ steps.explain_cache_output.outputs.real_cache_hit }} + +runs: + using: "composite" + steps: + - name: Generate random UUID + id: generate_random_uuid + run: | + random_uuid=$(uuidgen -r) + echo "::debug::Random uuid generated is $random_uuid. Should only cause a cache-miss" + echo "computed_uuid=$random_uuid" >> $GITHUB_OUTPUT + shell: bash + - name: Get pip cache directory + id: get_pip_cache_directory + run: | + if [[ -z '${{ inputs.custom_pip_cache_path }}' ]]; then + echo "pip_cache_path=$(pip cache dir)" >> $GITHUB_OUTPUT + else + echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT + fi + shell: bash + - name: Restore pip cache + id: restore_pip_cache + uses: actions/cache/restore@v4 + with: + key: ${{ steps.generate_random_uuid.outputs.computed_uuid }} + path: ${{ steps.get_pip_cache_directory.outputs.pip_cache_path }} + restore-keys: ${{ inputs.git_reference }}-pip-cache- + - name: Explain cache output + id: explain_cache_output + run: | + echo "::debug::Restore action for pip's cache returned cache-hit: ${{ steps.restore_pip_cache.outputs.cache-hit }} with cache-matched-key: ${{ steps.restore_pip_cache.outputs.cache-matched-key }}" + if [[ -z '${{ steps.restore_pip_cache.outputs.cache-matched-key }}' ]]; then + echo "real_cache_hit=false" >> $GITHUB_OUTPUT + else + echo "real_cache_hit=true" >> $GITHUB_OUTPUT + fi + shell: bash \ No newline at end of file diff --git a/actions/python_requirements/restore_virtualenv/action.yml b/actions/python_requirements/restore_virtualenv/action.yml new file mode 100644 index 0000000..1798a87 --- /dev/null +++ b/actions/python_requirements/restore_virtualenv/action.yml @@ -0,0 +1,43 @@ +name: Composite action restore Python virtual environment +description: Composite action to restore Python virtual environment +inputs: + virtual_environment_path: + description: Path to where virtual environment will be restored. + required: false + default: ".venv" + requirements_paths: + description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +outputs: + cache-hit: + description: Whether virtual environment was found in the cache or not. + value: ${{ steps.restore_virtual_environment.outputs.cache-hit }} + +runs: + using: "composite" + steps: + - name: Compute requirements files SHA256 hash + id: compute_requirements_files_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.requirements_paths }} + + - name: Restore virtual environment + id: restore_virtual_environment + uses: actions/cache/restore@v4 + with: + path: ${{ inputs.virtual_environment_path }} + key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} + + - name: Activate restored virtual environment + if: > + steps.restore_virtual_environment.outputs.cache-hit == 'true' + uses: ./.github/actions/python_requirements/create_virtualenv + with: + virtualenv_path: ${{ inputs.virtual_environment_path }} + activate_only: true \ No newline at end of file diff --git a/actions/python_requirements/save_pip_cache/action.yml b/actions/python_requirements/save_pip_cache/action.yml new file mode 100644 index 0000000..218e508 --- /dev/null +++ b/actions/python_requirements/save_pip_cache/action.yml @@ -0,0 +1,37 @@ +name: Composite action save pip's cache +description: Composite action to save pip's cache +inputs: + custom_pip_cache_path: + description: Path to pip cache. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +runs: + using: "composite" + steps: + # TODO non posso usare l'hash del file perchè quando vado ad aggiornare i requirements + # l'hash cambia e sicuramente non trovo la cache salvata + - name: Generate random UUID + id: generate_random_uuid + run: | + random_uuid=$(uuidgen -r) + echo "::debug::Random uuid generated is $random_uuid" + echo "computed_uuid=$random_uuid" >> $GITHUB_OUTPUT + shell: bash + - name: Get pip cache directory + id: get_pip_cache_directory + run: | + if [[ -z '${{ inputs.custom_pip_cache_path }}' ]]; then + echo "pip_cache_path=$(pip cache dir)" >> $GITHUB_OUTPUT + else + echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT + fi + shell: bash + - name: Save pip cache + uses: actions/cache/save@v4 + with: + path: ${{ steps.get_pip_cache_directory.outputs.pip_cache_path }} + key: ${{ inputs.git_reference }}-pip-cache-${{ steps.generate_random_uuid.outputs.computed_uuid }} \ No newline at end of file diff --git a/actions/python_requirements/save_virtualenv/action.yml b/actions/python_requirements/save_virtualenv/action.yml new file mode 100644 index 0000000..b93d66c --- /dev/null +++ b/actions/python_requirements/save_virtualenv/action.yml @@ -0,0 +1,29 @@ +name: Composite action save Python virtual environment +description: Composite action to save Python virtual environment +inputs: + virtual_environment_path: + description: Path to virtual environment. + required: false + default: ".venv" + requirements_paths: + description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. + required: false + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +runs: + using: "composite" + steps: + - name: Compute requirements files SHA256 hash + id: compute_requirements_files_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.requirements_paths }} + + - name: Cache virtual environment + uses: actions/cache/save@v4 + with: + path: ${{ inputs.virtual_environment_path }} + key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/workflows/_python.yml b/workflows/_python.yml index 04f71a0..1f6624f 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -248,7 +248,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python_version }} @@ -292,116 +292,97 @@ jobs: exit 1 shell: bash - - name: Create requirements-linters.txt - run: | - function check_linter_dependency_and_append_to_file { - # - # Function to check whether a specific linter is in the requirements file - # If it can be found inside the requirements, said linter dependency will be appended to a newly created requirements-linter.txt file. - # If the linter is not found inside the requirements file an error will be raised. - # - # 1st parameter: Name of the linter. - # 2nd parameter: Path of the requirements file. - # - if [[ -z $(grep -P "^$1[^a-zA-Z0-9_-].*" "$2") ]]; then - echo "::error::$1 dependency not found in $2 file!" - exit 1 - else - echo "$1 dependency found in $2!" - echo "$(grep -P ^$1[^a-zA-Z0-9_-].* $2)" >> requirements-linters.txt - fi - } - CI_REQUIREMENTS_LINTERS="${GITHUB_WORKSPACE}/.github/configurations/python_linters/requirements-linters.txt" - echo > requirements-linters.txt - - if [[ '${{ inputs.use_black}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "black" "$CI_REQUIREMENTS_LINTERS" - fi - - if [[ '${{ inputs.use_isort}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "isort" "$CI_REQUIREMENTS_LINTERS" - fi - - if [[ '${{ inputs.use_flake8}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "flake8" "$CI_REQUIREMENTS_LINTERS" - if [[ -n '${{ inputs.django_settings_module }}' ]]; then - check_linter_dependency_and_append_to_file "flake8-django" "$CI_REQUIREMENTS_LINTERS" - fi - fi + - name: Create linter requirements file + uses: ./.github/actions/python_requirements/create_linter_requirements_file + with: + install_from: ${{ inputs.install_from }} + django_settings_module: ${{ inputs.django_settings_module }} + use_autoflake: ${{ inputs.use_autoflake }} + use_bandit: ${{ inputs.use_bandit }} + use_flake8: ${{ inputs.use_flake8 }} + use_pylint: ${{ inputs.use_pylint }} - if [[ '${{ inputs.use_pylint}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "pylint" "$CI_REQUIREMENTS_LINTERS" - if [[ -n '${{ inputs.django_settings_module }}' ]]; then - check_linter_dependency_and_append_to_file "pylint-django" "$CI_REQUIREMENTS_LINTERS" - fi - fi + - name: Create dev requirements file + uses: ./.github/actions/python_requirements/create_dev_requirements_file + with: + install_from: ${{ inputs.install_from }} + use_coverage: ${{ inputs.use_coverage }} - if [[ '${{ inputs.use_bandit}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" - fi - if [[ '${{ inputs.use_autoflake}}' != 'false' ]]; then - check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" - fi - cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-linter.txt/') >> requirements-linters.txt 2>/dev/null || exit 0 - shell: bash - working-directory: ${{ inputs.install_from }} + - name: Create docs requirements file + uses: ./.github/actions/python_requirements/create_docs_requirements_file + with: + install_from: ${{ inputs.install_from }} + check_docs_directory: ${{ inputs.check_docs_directory }} + django_settings_module: ${{ inputs.django_settings_module }} - - name: Create requirements-dev.txt - run: | - echo > requirements-dev.txt - if [[ '${{ inputs.use_coverage }}' != 'false' ]]; then - echo "coverage>=7.3.2" >> requirements-dev.txt - fi - cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-dev.txt/') >> requirements-dev.txt 2>/dev/null || exit 0 - shell: bash - working-directory: ${{ inputs.install_from }} + - name: Restore Python virtual environment related to PR event + id: restore_python_virtual_environment_pr + uses: ./.github/actions/python_requirements/restore_virtualenv/ + with: + requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" - - name: Create requirements-docs.txt - run: | - echo > requirements-docs.txt - if [[ -n '${{ inputs.check_docs_directory }}' ]]; then - echo "rstcheck[sphinx]" >> requirements-docs.txt - echo "sphinx==7.2.6" >> requirements-docs.txt - echo "sphinx_rtd_theme==1.3.0" >> requirements-docs.txt - echo "sphinxcontrib-spelling==8.0.0" >> requirements-docs.txt - if [[ -n '${{ inputs.django_settings_module }}' ]]; then - echo "sphinxcontrib-django2==1.9" >> requirements-docs.txt - fi - cat $(echo ${{ inputs.requirements_path }} | sed -e 's/.txt/-docs.txt/') >> requirements-docs.txt 2>/dev/null || exit 0 - fi + - name: Restore Python virtual environment related to target branch + id: restore_python_virtual_environment_target_branch + if: steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/restore_virtualenv/ + with: + requirements_paths: ${{ inputs.requirements_path }} + git_reference: ${{ github.base_ref }} + + - name: Create Python virtual environment + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/create_virtualenv + + - name: Restore pip cache related to PR event + id: restore_pip_cache_pr + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/restore_pip_cache + + - name: Restore pip cache related to target branch + id: restore_pip_cache_target_branch + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' && + steps.restore_pip_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/restore_pip_cache + with: + git_reference: ${{ github.base_ref }} + + - name: Install project requirements + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_python_virtual_environment_target_branch.outputs.cache-hit != 'true' + run: pip install -r ${{ inputs.requirements_path }} shell: bash working-directory: ${{ inputs.install_from }} - - name: Check virtualenv cache - uses: syphar/restore-virtualenv@v1 - id: cache-virtualenv - with: - requirement_files: | - ${{ inputs.install_from }}/${{ inputs.requirements_path }} - ${{ inputs.install_from }}/requirements-dev.txt - ${{ inputs.install_from }}/requirements-linters.txt - ${{ inputs.install_from }}/requirements-docs.txt - - - name: Check pip cache - uses: syphar/restore-pip-download-cache@v1 - if: steps.cache-virtualenv.outputs.cache-hit != 'true' - with: - requirement_files: | - ${{ inputs.install_from }}/${{ inputs.requirements_path }} - ${{ inputs.install_from }}/requirements-dev.txt - ${{ inputs.install_from }}/requirements-linters.txt - ${{ inputs.install_from }}/requirements-docs.txt - - - name: Install requirements - if: steps.cache-virtualenv.outputs.cache-hit != 'true' + - name: Install other requirements + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' run: | - pip install -r ${{ inputs.requirements_path }} pip install -r requirements-dev.txt pip install -r requirements-linters.txt pip install -r requirements-docs.txt shell: bash working-directory: ${{ inputs.install_from }} + - name: Save Python virtual environment related to the PR event + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/save_virtualenv + with: + requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" + + - name: Save pip cache related to the PR event + if: > + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && + steps.restore_pip_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/python_requirements/save_pip_cache + - name: Run linters uses: ./.github/actions/python_linter if: inputs.use_black || inputs.use_isort || inputs.use_flake8 || inputs.use_pylint || inputs.use_bandit || inputs.use_autoflake diff --git a/workflows/create_apt_cache.yaml b/workflows/create_apt_cache.yaml index 2315fc9..06f26cc 100644 --- a/workflows/create_apt_cache.yaml +++ b/workflows/create_apt_cache.yaml @@ -13,27 +13,31 @@ on: # Path to APT requirements file - '.github/test/python_test/packages.txt' +# discard previous execution if you commit to a branch that is already running +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: create-cache: - name: Create cache for dependencies + name: Create cache for APT dependencies runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Remember to set the same APT requirements file path set before! - - name: Install dependencies + - name: Install APT dependencies run: | sudo apt-get update - sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < apt_packages.txt) + sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < .github/test/python_test/packages.txt) - name: Compute apt_packages.txt SHA256 hash id: compute_apt_packages_sha256_hash - run: | - COMPUTED_HASH=$(sha256sum apt_packages.txt | cut -d ' ' -f 1) - echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: .github/test/python_test/packages.txt - uses: actions/cache/save@v4 with: path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.cache_key }} + key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.computed_hash }} diff --git a/workflows/create_python_cache.yaml b/workflows/create_python_cache.yaml new file mode 100644 index 0000000..a6b65b5 --- /dev/null +++ b/workflows/create_python_cache.yaml @@ -0,0 +1,50 @@ +name: Create Python cache + +# GitHub will remove any cache entries that have not been accessed in over 7 days. + +# Only project dependencies will be cached here + +on: + push: + branches: + - main + - master + - develop + - dev + paths: + - '.github/test/python_test/requirements.txt' + +# discard previous execution if you commit to a branch that is already running +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + create-python-cache: + name: Create cache for Python dependencies + runs-on: ubuntu-latest + steps: + - name: Check out latest commit + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Set up Python's virtual environment + uses: ./.github/actions/python_requirements/create_virtualenv + + - name: Install Python dependencies + run: | + pip install -r .github/test/python_test/requirements.txt + working-directory: "." + + - name: Save pip cache + uses: ./.github/actions/python_requirements/save_pip_cache + + - name: Create virtual environment cache + uses: ./.github/actions/python_requirements/save_virtualenv + with: + requirements_paths: .github/test/python_test/requirements.txt + diff --git a/workflows/pull_request_automation.yml b/workflows/pull_request_automation.yml index 7c3ffb4..71deca6 100644 --- a/workflows/pull_request_automation.yml +++ b/workflows/pull_request_automation.yml @@ -101,6 +101,6 @@ jobs: env: >- {"KEY": "VALUE"} python_versions: >- - ["3.10"] + ["3.12"] max_timeout: 15 ubuntu_version: latest From 0d2f9315593cf942a98342ecbe5a9b270289329a Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:51:00 +0100 Subject: [PATCH 10/15] updated github actions versions (#218) --- .../save_pip_cache/action.yml | 2 - .github/workflows/_release_and_tag.yml | 4 +- .github/workflows/create_apt_cache.yaml | 14 ++++-- .github/workflows/create_python_cache.yaml | 50 +++++++++++++++++++ CHANGELOG.md | 3 ++ .../save_pip_cache/action.yml | 2 - workflows/_release_and_tag.yml | 4 +- 7 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/create_python_cache.yaml diff --git a/.github/actions/python_requirements/save_pip_cache/action.yml b/.github/actions/python_requirements/save_pip_cache/action.yml index 218e508..165bcf4 100644 --- a/.github/actions/python_requirements/save_pip_cache/action.yml +++ b/.github/actions/python_requirements/save_pip_cache/action.yml @@ -12,8 +12,6 @@ inputs: runs: using: "composite" steps: - # TODO non posso usare l'hash del file perchè quando vado ad aggiornare i requirements - # l'hash cambia e sicuramente non trovo la cache salvata - name: Generate random UUID id: generate_random_uuid run: | diff --git a/.github/workflows/_release_and_tag.yml b/.github/workflows/_release_and_tag.yml index e899456..92bf029 100644 --- a/.github/workflows/_release_and_tag.yml +++ b/.github/workflows/_release_and_tag.yml @@ -81,7 +81,7 @@ jobs: - name: Create Tag and Release id: create-release if: steps.check-tag.outputs.match == 'true' - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event.pull_request.title }} name: Version ${{ github.event.pull_request.title }} @@ -97,7 +97,7 @@ jobs: with: fetch-depth: 0 # otherwise, you do not retrieve the tags - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 if: steps.check-tag.outputs.match == 'true' && (inputs.publish_on_pypi || inputs.publish_on_test_pypi) with: python-version: "3.x" diff --git a/.github/workflows/create_apt_cache.yaml b/.github/workflows/create_apt_cache.yaml index 7cd6937..06f26cc 100644 --- a/.github/workflows/create_apt_cache.yaml +++ b/.github/workflows/create_apt_cache.yaml @@ -13,6 +13,10 @@ on: # Path to APT requirements file - '.github/test/python_test/packages.txt' +# discard previous execution if you commit to a branch that is already running +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: create-cache: @@ -25,15 +29,15 @@ jobs: - name: Install APT dependencies run: | sudo apt-get update - sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < apt_packages.txt) + sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < .github/test/python_test/packages.txt) - name: Compute apt_packages.txt SHA256 hash id: compute_apt_packages_sha256_hash - run: | - COMPUTED_HASH=$(sha256sum apt_packages.txt | cut -d ' ' -f 1) - echo "cache_key=$COMPUTED_HASH" >> $GITHUB_OUTPUT + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: .github/test/python_test/packages.txt - uses: actions/cache/save@v4 with: path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.cache_key }} + key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.computed_hash }} diff --git a/.github/workflows/create_python_cache.yaml b/.github/workflows/create_python_cache.yaml new file mode 100644 index 0000000..a6b65b5 --- /dev/null +++ b/.github/workflows/create_python_cache.yaml @@ -0,0 +1,50 @@ +name: Create Python cache + +# GitHub will remove any cache entries that have not been accessed in over 7 days. + +# Only project dependencies will be cached here + +on: + push: + branches: + - main + - master + - develop + - dev + paths: + - '.github/test/python_test/requirements.txt' + +# discard previous execution if you commit to a branch that is already running +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + create-python-cache: + name: Create cache for Python dependencies + runs-on: ubuntu-latest + steps: + - name: Check out latest commit + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Set up Python's virtual environment + uses: ./.github/actions/python_requirements/create_virtualenv + + - name: Install Python dependencies + run: | + pip install -r .github/test/python_test/requirements.txt + working-directory: "." + + - name: Save pip cache + uses: ./.github/actions/python_requirements/save_pip_cache + + - name: Create virtual environment cache + uses: ./.github/actions/python_requirements/save_virtualenv + with: + requirements_paths: .github/test/python_test/requirements.txt + diff --git a/CHANGELOG.md b/CHANGELOG.md index aa1d0af..9ff6f6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,3 +27,6 @@ * Removed `setup-python-dependencies` from `codeql/action.yml` since it has no effect anymore. See [this](https://github.blog/changelog/2024-01-23-codeql-2-16-python-dependency-installation-disabled-new-queries-and-bug-fixes/) for more information. * Linters versions in step `Create requirements-linters.txt` of `_python.yml` action are now computed according to `configurations/python_linters/requirements-linters.txt`. As of now, linter updates are only required in `configurations/python_linters/requirements-linters.txt`. * Reworked Python requirements caching. +* Updated some Github actions: + * setup-python v4 -> v5 + * action-gh-release v1 -> v2 diff --git a/actions/python_requirements/save_pip_cache/action.yml b/actions/python_requirements/save_pip_cache/action.yml index 218e508..165bcf4 100644 --- a/actions/python_requirements/save_pip_cache/action.yml +++ b/actions/python_requirements/save_pip_cache/action.yml @@ -12,8 +12,6 @@ inputs: runs: using: "composite" steps: - # TODO non posso usare l'hash del file perchè quando vado ad aggiornare i requirements - # l'hash cambia e sicuramente non trovo la cache salvata - name: Generate random UUID id: generate_random_uuid run: | diff --git a/workflows/_release_and_tag.yml b/workflows/_release_and_tag.yml index e899456..92bf029 100644 --- a/workflows/_release_and_tag.yml +++ b/workflows/_release_and_tag.yml @@ -81,7 +81,7 @@ jobs: - name: Create Tag and Release id: create-release if: steps.check-tag.outputs.match == 'true' - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event.pull_request.title }} name: Version ${{ github.event.pull_request.title }} @@ -97,7 +97,7 @@ jobs: with: fetch-depth: 0 # otherwise, you do not retrieve the tags - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 if: steps.check-tag.outputs.match == 'true' && (inputs.publish_on_pypi || inputs.publish_on_test_pypi) with: python-version: "3.x" From 4f21023a7327c5adc5a5746b16424fb1d4855249 Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Fri, 28 Mar 2025 17:07:41 +0100 Subject: [PATCH 11/15] Added documentation - part 2 (#220) * Last commit of the day * Last commit of the day 26 * last commit of the day * added docs * few fixes * fixed if condition * fixed .github * fixed missing shell in restore_apt_cache * fixed another bug :) * fixed another bug * a test * fix * fixed few problems with apt caching * fixed another mistake * removed leftover --- .github/actions/apt_requirements/action.yml | 57 ----- .../restore_apt_cache/README.md | 29 +++ .../restore_apt_cache/action.yml | 64 ++++++ .../apt_requirements/save_apt_cache/README.md | 22 ++ .../save_apt_cache/action.yml | 24 ++ .../actions/misc/compute_files_hash/README.md | 18 ++ .../misc/compute_files_hash/action.yml | 12 +- .../create_dev_requirements_file/README.md | 13 ++ .../create_docs_requirements_file/README.md | 12 + .../create_linter_requirements_file/README.md | 27 +++ .../create_virtualenv/README.md | 20 ++ .../create_virtualenv/action.yml | 2 + .../restore_pip_cache/README.md | 41 ++++ .../restore_pip_cache/action.yml | 5 +- .../restore_virtualenv/README.md | 30 +++ .../restore_virtualenv/action.yml | 6 +- .../save_pip_cache/README.md | 22 ++ .../save_pip_cache/action.yml | 7 +- .../save_virtualenv/README.md | 23 ++ .../save_virtualenv/action.yml | 8 +- .../python_linters/requirements-linters.txt | 3 + .github/workflows/README.md | 214 ++++++++++++++++++ .github/workflows/_detect_changes.yml | 16 +- .github/workflows/_node.yml | 3 +- .github/workflows/_python.yml | 85 ++++--- .github/workflows/create_apt_cache.yaml | 15 +- .github/workflows/create_python_cache.yaml | 2 +- CHANGELOG.md | 1 + actions/apt_requirements/action.yml | 57 ----- .../restore_apt_cache/README.md | 29 +++ .../restore_apt_cache/action.yml | 64 ++++++ .../apt_requirements/save_apt_cache/README.md | 22 ++ .../save_apt_cache/action.yml | 24 ++ actions/misc/compute_files_hash/README.md | 18 ++ actions/misc/compute_files_hash/action.yml | 12 +- .../create_dev_requirements_file/README.md | 13 ++ .../create_docs_requirements_file/README.md | 12 + .../create_linter_requirements_file/README.md | 27 +++ .../create_virtualenv/README.md | 20 ++ .../create_virtualenv/action.yml | 2 + .../restore_pip_cache/README.md | 41 ++++ .../restore_pip_cache/action.yml | 5 +- .../restore_virtualenv/README.md | 30 +++ .../restore_virtualenv/action.yml | 6 +- .../save_pip_cache/README.md | 22 ++ .../save_pip_cache/action.yml | 7 +- .../save_virtualenv/README.md | 23 ++ .../save_virtualenv/action.yml | 8 +- .../python_linters/requirements-linters.txt | 3 + workflows/README.md | 214 ++++++++++++++++++ workflows/_detect_changes.yml | 16 +- workflows/_node.yml | 3 +- workflows/_python.yml | 85 ++++--- workflows/create_apt_cache.yaml | 15 +- workflows/create_python_cache.yaml | 2 +- 55 files changed, 1321 insertions(+), 240 deletions(-) delete mode 100644 .github/actions/apt_requirements/action.yml create mode 100644 .github/actions/apt_requirements/restore_apt_cache/README.md create mode 100644 .github/actions/apt_requirements/restore_apt_cache/action.yml create mode 100644 .github/actions/apt_requirements/save_apt_cache/README.md create mode 100644 .github/actions/apt_requirements/save_apt_cache/action.yml create mode 100644 .github/actions/misc/compute_files_hash/README.md create mode 100644 .github/actions/python_requirements/create_dev_requirements_file/README.md create mode 100644 .github/actions/python_requirements/create_docs_requirements_file/README.md create mode 100644 .github/actions/python_requirements/create_linter_requirements_file/README.md create mode 100644 .github/actions/python_requirements/create_virtualenv/README.md create mode 100644 .github/actions/python_requirements/restore_pip_cache/README.md create mode 100644 .github/actions/python_requirements/restore_virtualenv/README.md create mode 100644 .github/actions/python_requirements/save_pip_cache/README.md create mode 100644 .github/actions/python_requirements/save_virtualenv/README.md create mode 100644 .github/workflows/README.md delete mode 100644 actions/apt_requirements/action.yml create mode 100644 actions/apt_requirements/restore_apt_cache/README.md create mode 100644 actions/apt_requirements/restore_apt_cache/action.yml create mode 100644 actions/apt_requirements/save_apt_cache/README.md create mode 100644 actions/apt_requirements/save_apt_cache/action.yml create mode 100644 actions/misc/compute_files_hash/README.md create mode 100644 actions/python_requirements/create_dev_requirements_file/README.md create mode 100644 actions/python_requirements/create_docs_requirements_file/README.md create mode 100644 actions/python_requirements/create_linter_requirements_file/README.md create mode 100644 actions/python_requirements/create_virtualenv/README.md create mode 100644 actions/python_requirements/restore_pip_cache/README.md create mode 100644 actions/python_requirements/restore_virtualenv/README.md create mode 100644 actions/python_requirements/save_pip_cache/README.md create mode 100644 actions/python_requirements/save_virtualenv/README.md create mode 100644 workflows/README.md diff --git a/.github/actions/apt_requirements/action.yml b/.github/actions/apt_requirements/action.yml deleted file mode 100644 index 7134837..0000000 --- a/.github/actions/apt_requirements/action.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Composite action install APT requirements -description: Composite action to install APT requirements -inputs: - requirements_file: - description: Requirements file - required: true - -runs: - using: "composite" - steps: - - name: Compute apt requirements file SHA256 hash - id: compute_apt_requirements_file_sha256_hash - uses: ./.github/actions/misc/compute_files_hash - with: - file_paths: ${{ inputs.requirements_file }} - - # Vital to be able to restore cache - # If write permission is not set, a permissions error will be raised - - name: Modification to /var/cache/apt/archives permissions - run: | - sudo chmod a+w /var/cache/apt/archives - shell: bash - - - uses: actions/cache/restore@v4 - id: restore_cache_from_parent_branch - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - - - uses: actions/cache/restore@v4 - id: restore_cache_from_current_branch - if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - - - name: Refresh repositories - if: > - steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && - steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' - run: | - sudo apt-get update - shell: bash - - - name: Install requirements - run: | - sudo apt-get install -y --no-install-recommends $(tr '\n' ' ' < ${{ inputs.requirements_file }}) - shell: bash - - - uses: actions/cache/save@v4 - id: cache_apt_requirements_for_current_branch - if: > - steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && - steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/.github/actions/apt_requirements/restore_apt_cache/README.md b/.github/actions/apt_requirements/restore_apt_cache/README.md new file mode 100644 index 0000000..046b58e --- /dev/null +++ b/.github/actions/apt_requirements/restore_apt_cache/README.md @@ -0,0 +1,29 @@ +# Composite action restore APT cache + +This action restores an APT cache from GitHub's cache. + +Combined with [**save_apt_cache**](../save_apt_cache/README.md), it helps save time by avoiding the download of APT requirements. + +The action is composed of five steps: + +1. **Compute APT requirements files SHA256 hash** - This step uses [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) action to compute a single SHA256 hash of the APT requirements file described by the *apt_rquirements_file_path* input variable. The computed SHA256 hash will be part of the cache key. +2. **Backup `/var/cache/apt/archives permissions`** - This step backs up the permissions associated to the `/var/cache/apt/archives` directory. So, after restoring the APT cache they can be restored to the original ones. +3. **Add write permissions for all to `/var/cache/apt/archives`** - This step sets the write permission to the `/var/cache/apt/archives`. This is crucial because the [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) GitHub's action needs to be able to write to it. Without setting the correct write permission, a permission error is raised. +4. **Restore APT cache** - This step restores the APT cache. It uses the GitHub's [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action with the following parameters: + * **path** - A list of files, directories, or paths to restore - set to `/var/cache/apt/archives/*.deb`. + * **key** - An explicit key for a cache entry - set to the combination of three strings: + * *git_reference*, provided as an input to the action. + * A static part, `-apt-` + * The previously computed SHA256 hash of the APT requirements file. +5. **Restore original permissions to `/var/cache/apt/archives` and delete backup** - This step restore the original permissions to the `/var/cache/apt/archives` directory. Finally, the backup file is deleted. + +## Documentation + +### Inputs + +* **apt_requirements_file_path** - Required - Path to the APT requirements file. It will be used to compute a SHA256 hash used in the cache key. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. + +### Outputs + +* **cache-hit** - A boolean value which is true when APT cache is found in the GitHub's cache, false otherwise. diff --git a/.github/actions/apt_requirements/restore_apt_cache/action.yml b/.github/actions/apt_requirements/restore_apt_cache/action.yml new file mode 100644 index 0000000..282935b --- /dev/null +++ b/.github/actions/apt_requirements/restore_apt_cache/action.yml @@ -0,0 +1,64 @@ +name: Composite action restore APT cache +description: Composite action to restore APT cache +inputs: + apt_requirements_file_path: + description: Path to the APT requirements file + required: true + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +outputs: + cache-hit: + description: Whether the APT cache was found in the GitHub's cache or not. + value: ${{ steps.restore_apt_cache.outputs.cache-hit }} + + +runs: + using: "composite" + steps: + - name: Compute APT requirements file SHA256 hash + id: compute_apt_requirements_file_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.apt_requirements_file_path }} + + - name: Backup /var/cache/apt/archives permissions + id: backup_apt_cache_dir_permissions + run: | + PERMISSIONS_FILE_PATH="/tmp/apt_cache_dir_permissions.facl" + echo "apt_cache_dir_permissions_file=$PERMISSIONS_FILE_PATH" > $GITHUB_OUTPUT + sudo getfacl -p /var/cache/apt/archives > $PERMISSIONS_FILE_PATH + ARCHIVES_PERMISSIONS=$(ls -ld /var/cache/apt/archives) + echo "::debug::Original permissions given to /var/cache/apt/archives: $ARCHIVES_PERMISSIONS" + echo "::debug::Created /var/cache/apt/archives permissions backup to $PERMISSIONS_FILE_PATH" + shell: bash + + # Vital to be able to restore cache + # If write permission is not set, a permissions error will be raised + - name: Add write permission for all to /var/cache/apt/archives + run: | + sudo chmod a+w /var/cache/apt/archives + ARCHIVES_NEW_PERMISSIONS=$(ls -ld /var/cache/apt/archives) + echo "::debug::New permissions given to /var/cache/apt/archives: $ARCHIVES_NEW_PERMISSIONS" + shell: bash + + - name: Restore APT cache + uses: actions/cache/restore@v4 + id: restore_apt_cache + with: + path: /var/cache/apt/archives/*.deb + key: ${{ inputs.git_reference }}-apt-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} + + - name: Restore original permissions to /var/cache/apt/archives and delete backup + run: | + PERMISSIONS_FILE_PATH=${{ steps.backup_apt_cache_dir_permissions.outputs.apt_cache_dir_permissions_file }} + sudo setfacl --restore="$PERMISSIONS_FILE_PATH" + ARCHIVES_RESTORED_PERMISSIONS=$(ls -ld /var/cache/apt/archives) + echo "::debug::Restored original permissions to /var/cache/apt/archives: $ARCHIVES_RESTORED_PERMISSIONS" + if [[ -f "$PERMISSIONS_FILE_PATH" ]]; then + sudo rm "$PERMISSIONS_FILE_PATH" + echo "::debug::Correctly removed $PERMISSIONS_FILE_PATH permissions backup file" + fi + shell: bash \ No newline at end of file diff --git a/.github/actions/apt_requirements/save_apt_cache/README.md b/.github/actions/apt_requirements/save_apt_cache/README.md new file mode 100644 index 0000000..4d8dca8 --- /dev/null +++ b/.github/actions/apt_requirements/save_apt_cache/README.md @@ -0,0 +1,22 @@ +# Composite action save APT cache + +This action saves the APT cache, almost always located at `/var/cache/apt/archives/*.deb` to the GitHub's cache. + +Combined with [**restore_apt_cache**](../restore_apt_cache/README.md) helps save time by avoiding the download of APT requirements. + +The action is composed of two steps: + +1. **Compute APT requirements file SHA256 hash** - This step uses the [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) action to compute the SHA256 hash of the APT requriments file that will be part of the cache key. +2. **Save APT cache** - This step does the real caching on GitHub. The GitHub's [**cache/save**](https://github.com/actions/cache/blob/main/save/README.md) is used with the following parameters: + 1. **path** - A list of files, directories, or paths to cache - set to `/var/cache/apt/archives/*.deb` to save all `*.deb` files in APT cache. + 2. **key** - An explicit key for a cache entry - set to the combination of three strings: + 1. *git_reference*, provided as an input to the action. + 2. A static part, `-apt-` + 3. The previously computed SHA256 hash of the APT requirements file. + +## Documentation + +### Inputs + +* **apt_requirements_file_path** - Required - Path to the APT requirements file. It will be used to compute a SHA256 hash used in the cache key. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. diff --git a/.github/actions/apt_requirements/save_apt_cache/action.yml b/.github/actions/apt_requirements/save_apt_cache/action.yml new file mode 100644 index 0000000..af41cfd --- /dev/null +++ b/.github/actions/apt_requirements/save_apt_cache/action.yml @@ -0,0 +1,24 @@ +name: Composite action save APT cache +description: Composite action to save APT cache +inputs: + apt_requirements_file_path: + description: Path to the APT requirements file + required: true + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +runs: + using: "composite" + steps: + - name: Compute APT requiremments file SHA256 hash + id: compute_apt_requirements_file_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.apt_requirements_file_path }} + - name: Save APT cache + uses: actions/cache/save@v4 + with: + path: /var/cache/apt/archives/*.deb + key: ${{ inputs.git_reference }}-apt-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/.github/actions/misc/compute_files_hash/README.md b/.github/actions/misc/compute_files_hash/README.md new file mode 100644 index 0000000..f1c594f --- /dev/null +++ b/.github/actions/misc/compute_files_hash/README.md @@ -0,0 +1,18 @@ +# Composite action compute files hash + +This action computes a single SHA256 hash of one or more files. +Given a **space separated list of file paths**, a new file is created by concatenating all those files together. Then the SHA256 hash of the newly created file is computed and returned as the output. + +Before being joined together, each file is tested to ensure that it **exists** and that it is **a regular file**. + +This action is useful when saving/restoring a cache in which a unique key is required. As a matter of fact, the hash is used as a part of the hash key. + +## Documentation + +### Inputs + +* `file_paths` - Mandatory - Space separated list of file paths for which a single SHA256 hash will be computed. + +### Outputs + +* `computed_hash` - A SHA256 hash of the file obtained by joining (concatenating) all input files together. diff --git a/.github/actions/misc/compute_files_hash/action.yml b/.github/actions/misc/compute_files_hash/action.yml index 2c3b905..fca2a53 100644 --- a/.github/actions/misc/compute_files_hash/action.yml +++ b/.github/actions/misc/compute_files_hash/action.yml @@ -2,8 +2,8 @@ name: Composite action compute files hash description: Composite action to compute a single hash of one or more files inputs: file_paths: - description: Comma separeted list of files. - required: false + description: Space separeted list of files for which a single SHA256 hash will be computed. + required: true outputs: computed_hash: @@ -16,11 +16,13 @@ runs: - name: Compute files SHA256 hash id: compute_files_sha256_hash run: | + if [[ -z '${{ inputs.file_paths }}' ]]; then + echo "::error::file_paths cannot be empty!" + exit 1 + fi JOINED_FILES="cat " # Create a bash array of file paths - IFS=',' read -r -a files <<< "${{ inputs.file_paths }}" - echo "::debug::File paths array is composed by: ${files[@]}" - for file in ${files[@]}; + for file in ${{ inputs.file_paths }}; do if [[ -f $file ]]; then # Concat file path to cat command diff --git a/.github/actions/python_requirements/create_dev_requirements_file/README.md b/.github/actions/python_requirements/create_dev_requirements_file/README.md new file mode 100644 index 0000000..ae32be0 --- /dev/null +++ b/.github/actions/python_requirements/create_dev_requirements_file/README.md @@ -0,0 +1,13 @@ +# Composite action create Python dev requirements file + +This action creates the `requirements-dev.txt` file which will contain all **development dependencies**. + +As of today, the only development dependency supported is `coverage`. + +## Documentation + +### Inputs + +* **install_from** - Optional - The path used as working directory when creating the `requirements-dev.txt` file. It defaults to the current directory (i.e. `.`). +* **project_dev_requirements_file** - Optional - The path of a project `requirements-dev.txt`. This was designed in case development requirements other than coverage are required. If specified, the dependencies in the project `requirements-dev.txt` will be appended in the newly created `requirements-dev.txt`. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no custom `requirements-dev.txt`**. +* **use_coverage** - Optional - Whether to use coverage or not. It defaults to false. diff --git a/.github/actions/python_requirements/create_docs_requirements_file/README.md b/.github/actions/python_requirements/create_docs_requirements_file/README.md new file mode 100644 index 0000000..913192f --- /dev/null +++ b/.github/actions/python_requirements/create_docs_requirements_file/README.md @@ -0,0 +1,12 @@ +# Composite action create Python docs requirements file + +This action creates the `requirements-docs.txt` file. This is a Python requirements file that will contain all **dependencies required to build the documentation**. + +## Documentation + +### Inputs + +* **install_from** - Optional - The path used as working directory when creating the `requirements-docs.txt` file. It defaults to the current directory (i.e. `.`). +* **project_docs_requirements_file** - Optional - The path of a project `requirements-docs.txt`. This was designed in case requirements to build documentation other than rstcheck, sphinx, sphinx_rtd_theme, sphinxcontrib-spelling and sphinxcontrib-django2 are required. If specified, the dependencies in the project `requirements-docs.txt` will be appended in the newly created `requirements-docs.txt`. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no custom `requirements-docs.txt`**. +* **django_settings_module** - Optional - Path to the Django settings file. It's used to make GitHub action aware of Django presence. In this case, `sphinxcontrib-django2` is also added to the newly created requirement file. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no Django settings file**. +* **check_docs_directory** - Optional - Path that will be used by rstcheck to check documentation. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **documentation won't be checked**. diff --git a/.github/actions/python_requirements/create_linter_requirements_file/README.md b/.github/actions/python_requirements/create_linter_requirements_file/README.md new file mode 100644 index 0000000..9be5aa9 --- /dev/null +++ b/.github/actions/python_requirements/create_linter_requirements_file/README.md @@ -0,0 +1,27 @@ +# Composite action create Python linter requirements file + +This action creates the `requirements-linters.txt` file which will contain all **linter dependencies** required by the CI. +The user can then choose which linters will be run, and hence written to the `requirements-linters.txt`, by the CI by setting some flags to true like *use_black*. + +As of today only the following linters are supported: + +* `autoflake` +* `bandit` +* `black` +* `flake8` +* `flake8-django` +* `isort` +* `pylint` +* `pylint-django` + +## Documentation + +### Inputs + +* **install_from** - Optional - The path used as working directory when creating the `requirements-linters.txt` file. It defaults to the current directory (i.e. `.`). +* `project_linter_requirements_file` - Optional - The path of a project `requirements-linters.txt`. This was designed in case requirements for linters other than `autoflake`, `bandit`, `black`, `flake8`, `flake8-django`, `isort`, `pylint` and `pylint-django` are required. If specified, the dependencies in the project `requirements-linters.txt` will be appended in the newly created `requirements-linters.txt`. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no custom `requirements-linters.txt`**. +* **django_settings_module** - Optional - Path to the Django settings file. It's used to make GitHub action aware of Django presence. In the case of a Django project, `flake8-django` and `pylint-django`, may be used and hence they will be added to the newly created requirements file. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no Django settings file**. +* **use_autoflake** - Optional - Flag to state whether to use or not `autoflake` linter. It defaults to false. +* **use_bandit** - Optional - Flag to state whether to use or not `bandit` linter. It defaults to false. +* **use_flake8** - Optional - Flag to state whether to use or not `flake8` linter. It defaults to false. +* **use_pylint** - Optional - Flag to state whether to use or not `pylint` linter. It defaults to false. diff --git a/.github/actions/python_requirements/create_virtualenv/README.md b/.github/actions/python_requirements/create_virtualenv/README.md new file mode 100644 index 0000000..8f3361a --- /dev/null +++ b/.github/actions/python_requirements/create_virtualenv/README.md @@ -0,0 +1,20 @@ +# Composite action create Python virtual environment + +This GitHub action creates a Python virtual environment using Python's `venv` module. + +When the *activate_only* flag set is to true, the virtual environment at *virtualenv_path* will only be activated—**no creation will take place**. + +NOTE: + +To activate a Python virtual environment, the `activate` script is often used. +However, in a GitHub Action environment, this is not enough because environment variables are "lost" at the end of the Action. For this we need to do two things: + +1. Append the `VIRTUAL_ENV` environment variable to the `GITHUB_ENV` environment file. The [`GITHUB_ENV`](https://docs.github.com/en/enterprise-cloud@latest/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-environment-variable) files makes environment variables available to any subsequent steps in a workflow job. Finally, it's important to note that `VIRTUAL_ENV` variable is created by the `activate` script and contains the path to the virtual environment. +2. Prepend the virtual environment's `bin` path to the system PATH. To allow also any subsequent steps in a workflow to be able to use it, [`GITHUB_PATH`](https://docs.github.com/en/enterprise-cloud@latest/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-system-path) is employed. + +## Documentation + +### Inputs + +* **virtualenv_path** - Optional - The path where the virtual environment will be created. It defaults to `.venv`. +* **activate_only** - Optional - Flag that states whether to only activate the virtual environment. If false, a new virtual environment will be created before being activated. It defaults to false. \ No newline at end of file diff --git a/.github/actions/python_requirements/create_virtualenv/action.yml b/.github/actions/python_requirements/create_virtualenv/action.yml index 00a40a4..02dcb93 100644 --- a/.github/actions/python_requirements/create_virtualenv/action.yml +++ b/.github/actions/python_requirements/create_virtualenv/action.yml @@ -22,5 +22,7 @@ runs: run: | source ${{ inputs.virtualenv_path }}/bin/activate echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV + echo "::debug::Virtual environment path is $VIRTUAL_ENV" echo "$VIRTUAL_ENV/bin" >> $GITHUB_PATH + echo "::debug::PATH environment variable state after $VIRTUAL_ENV/bin path being added to it: $GITHUB_PATH" shell: bash diff --git a/.github/actions/python_requirements/restore_pip_cache/README.md b/.github/actions/python_requirements/restore_pip_cache/README.md new file mode 100644 index 0000000..92a2a2f --- /dev/null +++ b/.github/actions/python_requirements/restore_pip_cache/README.md @@ -0,0 +1,41 @@ +# Composite action restore pip cache + +This action restores the pip download cache from GitHub's cache. + +The action is composed of four steps: + +1. **Generate random UUID** - This step computes a random UUID, using the shell command `uuidgen`, which will be part of the cache key. Since pip cache will always be restored when a virtual environment is not found on GitHub's cache, a random UUID is required to generate a cache miss. +2. **Get pip cache directory** - This step retrieves the path to the pip cache. If *custom_pip_cache_path* is not an empty string, it will be used as pip cache path. Otherwise, the pip cache will be computed using `pip cache dir`. +3. **Restore pip cache** - This step performs the heavy lifting of the restoring. Using GitHub's [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action, the cache is restored using a **partial match**. This is performed by setting the following [inputs](https://github.com/actions/cache/tree/main/restore#inputs): + 1. **key** - an explicit key for a cache entry - will be set to a random UUID which will always trigger a cache miss. + 2. **path** - a list of files, directories, paths to restore - will be set to the pip download cache path. + 3. **restore-keys** - an ordered list of prefix-matched keys to use for restoring stale cache if no cache hit occurred for key - will be set to `-pip-cache-` to restore the most recent pip cache for the chosen git reference. +4. **Explain cache output** - This step analyze the results of the [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action and sets *real_cache_hit* environment variable to true if there was a match, false otherwise. This is necessary because, in the case of a **partial match**, the *cache-hit*, output of [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md), will be false. Instead, we use the `cache-matched-key`, another output of [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md), which contains a reference for both **partial** and full matches, but will be empty in the case of a cache miss. + +NOTE: + +This action, despite seeming a bit unusual, is correct because GitHub does not allow cache updates or overwrites. + +Let's think about a real-world scenario: + +A user updates the requirements file. + +In this case our query to GitHub's cache for the previously cached virtual environment will **always** miss. This happens because changing the requirements file results in a new SHA256 hash, so the cache key changes. + +Thus, we aim to restore the pip cache to at least *mitigate* the impact of the changes in the requirements. Specifically, we want to save time by avoiding the download of packages that did not change. + +Next, we try to query the GitHub's cache for the previously cached pip cache. However, there are a few issues: + +1. We cannot use the SHA256 of the requirements file because it has changed, leading to cache misses. +2. We cannot create a cache key without a random component because, as said earlier, GitHub does not allow overwriting or updating of a cache item. For example, a cache key like `develop-pip-cache-` would generate an error when attempting to save a new cache if one already exists with the same name. + +## Documentation + +### Inputs + +* **custom_pip_cache** - Optional - Path to the pip cache. It can be used for setting a custom pip cache path. It defaults to an empty string. In this case, the pip cache path will be computed using `pip cache dir`. More information regarding the previous command is available [here](https://pip.pypa.io/en/stable/cli/pip_cache/#description) +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. + +### Outputs + +* **cache-hit** - A boolean value which states whether pip cache was found on GitHub's cache or not. diff --git a/.github/actions/python_requirements/restore_pip_cache/action.yml b/.github/actions/python_requirements/restore_pip_cache/action.yml index 0c4f93b..e4568f7 100644 --- a/.github/actions/python_requirements/restore_pip_cache/action.yml +++ b/.github/actions/python_requirements/restore_pip_cache/action.yml @@ -1,5 +1,5 @@ -name: Composite action restore pip's cache -description: Composite action to restore pip's cache +name: Composite action restore pip cache +description: Composite action to restore pip cache inputs: custom_pip_cache_path: description: Path to pip cache. @@ -32,6 +32,7 @@ runs: else echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT fi + echo "::debug::Pip cache path $pip_cache_path" shell: bash - name: Restore pip cache id: restore_pip_cache diff --git a/.github/actions/python_requirements/restore_virtualenv/README.md b/.github/actions/python_requirements/restore_virtualenv/README.md new file mode 100644 index 0000000..e40a3c1 --- /dev/null +++ b/.github/actions/python_requirements/restore_virtualenv/README.md @@ -0,0 +1,30 @@ +# Composite action restore Python virtual environment + +This action restores a Python virtual environment from GitHub's cache. + +Combined with [**save_virtualenv**](../save_virtualenv/README.md), **it helps save time by avoiding the installation of Python requirements**. + +The action is composed of three steps: + +1. **Compute requirements files SHA256 hash** - This step uses [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) action to compute a single SHA256 hash of the files described by the *requirements_paths*. The computed SHA256 hash will be part of the cache key. +2. **Restore virtual environment** - This step does the heavy lifting of restoring the virtual environment from GitHub's cache. It uses the GitHub's [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action with the following parameters: + * **path** - A list of files, directories, or paths to restore - set to the virtual environment path input variable *virtual_environment_path*. + * **key** - An explicit key for a cache entry - set to the combination of three strings: + * *git_reference*, provided as an input to the action. + * A static part, `-venv-` + * The previously computed SHA256 hash of the requirements files. +3. **Activate restored virtual environment** - If the Python virtual environment was found in the GitHub's cache, it needs to be activated. This is performed using [**python_requirements/create_virtualenv**](../create_virtualenv/README.md) action with the following parameters: + * **virtualenv_path** - set to the Python virtual environment path. + * **activate_only** - set to true because it doesn't need to be created. + +## Documentation + +### Inputs + +* **virtual_environment_path** - Optional - Path where the virtual environment is located. It may be used to provide a custom path for the virtual environment. It defaults to `.venv`. +* **requirements_paths** - Required - A space separated list of requirements file paths. They will be used to compute a SHA256 hash used in the cache key. It defaults to an empty string. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. + +### Outputs + +* **cache-hit** - A boolean value which is true when virtual environment is found in the GitHub's cache, false otherwise. diff --git a/.github/actions/python_requirements/restore_virtualenv/action.yml b/.github/actions/python_requirements/restore_virtualenv/action.yml index 1798a87..cd76c98 100644 --- a/.github/actions/python_requirements/restore_virtualenv/action.yml +++ b/.github/actions/python_requirements/restore_virtualenv/action.yml @@ -6,8 +6,8 @@ inputs: required: false default: ".venv" requirements_paths: - description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. - required: false + description: Space separeted list of requirement files. They will be used to compute the hash for the cache key. + required: true git_reference: description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. required: false @@ -32,7 +32,7 @@ runs: uses: actions/cache/restore@v4 with: path: ${{ inputs.virtual_environment_path }} - key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} + key: ${{ inputs.git_reference }}-venv-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} - name: Activate restored virtual environment if: > diff --git a/.github/actions/python_requirements/save_pip_cache/README.md b/.github/actions/python_requirements/save_pip_cache/README.md new file mode 100644 index 0000000..e3950a0 --- /dev/null +++ b/.github/actions/python_requirements/save_pip_cache/README.md @@ -0,0 +1,22 @@ +# Composite action save pip cache + +This action saves the pip download cache. + +Every time a user runs `pip install `, pip downloads the package and all its dependencies.The packages are saved in a directory which, by default, is located at `~/.cache/pip`. +Saving this cache in GitHub's cache allows us to save time when installing those packages. As a matter of fact, before installing packages, pip's cache can be restored using [**restore_pip_cache**](../restore_pip_cache/README.md) action. + +The action is composed of three steps: + +1. **Generate random UUID** - This step computes a random UUID, using shell command `uuidgen`, which will be part of the cache key. The uniqueness of the UUID ensures that there will be no collisions between cache keys, which is crucial because **GitHub won't allow the creation of two caches with the same key** (cache update/overwrite **is not supported**). +2. **Get pip cache directory** - This step retrieves the path to the pip cache. If *custom_pip_cache_path* is not an empty string, it will be used as pip cache path. Otherwise, the pip cache will be computed using `pip cache dir`. +3. **Save pip cache** - This step performs the heavy lifting of the caching. Using GitHub's [**cache/save**](https://github.com/actions/cache/blob/main/save/README.md) action, the cache is saved with a key composed of: + 1. The git reference input, *git_reference* + 2. A static part, `pip-cache` + 3. The previously computed UUID + +## Documentation + +### Inputs + +* **custom_pip_cache** - Optional - Path to the pip cache. It can be used for setting a custom pip cache path. It defaults to an empty string. In this case, the pip cache path will be computed using `pip cache dir`. More information regarding the previous command is available [here](https://pip.pypa.io/en/stable/cli/pip_cache/#description) +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. diff --git a/.github/actions/python_requirements/save_pip_cache/action.yml b/.github/actions/python_requirements/save_pip_cache/action.yml index 165bcf4..d98e398 100644 --- a/.github/actions/python_requirements/save_pip_cache/action.yml +++ b/.github/actions/python_requirements/save_pip_cache/action.yml @@ -1,8 +1,8 @@ -name: Composite action save pip's cache -description: Composite action to save pip's cache +name: Composite action save pip cache +description: Composite action to save pip cache inputs: custom_pip_cache_path: - description: Path to pip cache. + description: Path to the pip cache. required: false git_reference: description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. @@ -27,6 +27,7 @@ runs: else echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT fi + echo "::debug::The pip cache path is $pip_cache_path" shell: bash - name: Save pip cache uses: actions/cache/save@v4 diff --git a/.github/actions/python_requirements/save_virtualenv/README.md b/.github/actions/python_requirements/save_virtualenv/README.md new file mode 100644 index 0000000..19d9ab5 --- /dev/null +++ b/.github/actions/python_requirements/save_virtualenv/README.md @@ -0,0 +1,23 @@ +# Composite action save Python virtual environment + +This action saves a Python virtual environment to GitHub's cache. + +Combined with [**restore_virtualenv**](../restore_virtualenv/README.md), **it helps save time by avoiding the installation of Python requirements**. + +The action is composed of two steps: + +1. **Compute requirements files SHA256 hash** - This step uses [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) to compute a single SHA256 hash of the files described by the *requirements_paths*. The computed SHA256 hash will be part of the cache key. +2. **Cache virtual environment** - This step does the heavy lifting of saving the virtual environment to GitHub's cache. It uses the GitHub's [**cache/save**](https://github.com/actions/cache/blob/main/save/README.md) action with the following parameters: + 1. **path** - A list of files, directories, or paths to cache - set to the virtual environment path input variable *virtual_environment_path*. + 2. **key** - An explicit key for a cache entry - set to the combination of three strings: + 1. *git_reference*, provided as an input to the action. + 2. A static part, `-venv-` + 3. The previously computed SHA256 hash of the requirements files. + +## Documentation + +### Inputs + +* **virtual_environment_path** - Optional - Path where the virtual environment is located. It may be used to provide a custom path for the virtual environment. It defaults to `.venv`. +* **requirements_paths** - Required - A space separated list of requirements file paths. They will be used to compute a SHA256 hash used in the cache key. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. diff --git a/.github/actions/python_requirements/save_virtualenv/action.yml b/.github/actions/python_requirements/save_virtualenv/action.yml index b93d66c..6c6c66c 100644 --- a/.github/actions/python_requirements/save_virtualenv/action.yml +++ b/.github/actions/python_requirements/save_virtualenv/action.yml @@ -2,12 +2,12 @@ name: Composite action save Python virtual environment description: Composite action to save Python virtual environment inputs: virtual_environment_path: - description: Path to virtual environment. + description: Path to the virtual environment. required: false default: ".venv" requirements_paths: - description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. - required: false + description: Space separeted list of requirements files. They will be used to compute the hash for the cache key. + required: true git_reference: description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. required: false @@ -26,4 +26,4 @@ runs: uses: actions/cache/save@v4 with: path: ${{ inputs.virtual_environment_path }} - key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} \ No newline at end of file + key: ${{ inputs.git_reference }}-venv-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/.github/configurations/python_linters/requirements-linters.txt b/.github/configurations/python_linters/requirements-linters.txt index 1f6b203..d8e8a4c 100644 --- a/.github/configurations/python_linters/requirements-linters.txt +++ b/.github/configurations/python_linters/requirements-linters.txt @@ -1,6 +1,9 @@ autoflake~=2.3.1 bandit~=1.8.3 black~=25.1.0 +# use fork since main repo is not updated +# see https://github.com/rocioar/flake8-django/pull/134 +# Note: python 3.12 is not supported flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b flake8~=7.1.2 isort~=6.0.1 diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..5bbea49 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,214 @@ +# Worflows + +## [Reusable detect changes workflow](_detect_changes.yml) + +This sub workflow detects and enumerates the changes between two branches. + +It is composed of five steps: + +1. **Check out PR target branch** - This step checks out the latest commit of the PR target branch for the current repository. This workflow was designed to detect changes when a PR to a target branch was created. Therefore, the latest commit of the target branch must be checked out as the first step. To achieve this, GitHub's [**checkout**](https://github.com/actions/checkout) action is used with the following parameters: + 1. **ref** - The branch, tag or SHA to checkout - It is set to `github.base_ref`, which corresponds to the **PR target branch**. +2. **Check out source branch latest commit** - This step checks out the latest commit of the source branch on top of the previous one. To do so, GitHub's [**checkout**](https://github.com/actions/checkout) action is used with the following parameters: + 1. **clean** - Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching - It is set to false, which means **do not delete untracked files**. +3. **Generate summary** - This step creates the title for the action summary. As a matter of fact, the detected changes will be reported below the title in the summary section. The step is performed only if one or both *backend_directories* and *frontend_directories* inputs are not empty. +4. **Generate diffs for backend** - This step detects and enumerates the files that changed between the two branches. This is performed using [`git diff`](https://git-scm.com/docs/git-diff) command. Specifically, the code instructs git to show the changes in the *backend_directories* relative to `origin/` (the target branch). During this process, the [**pathspec**](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec) is used to exclude files or directories specified in the *backend_exclusions* input. The changes are then enumerated and output through the *backend* variable. +5. **Generate diffs for frontend** - This step follow the same pattern as the **Generate diffs for backend** step but for the frontend directories. + +### Documentation + +#### Inputs + +* **backend_directories** - Optional - Space separated list of backend directories to check for changes. By default, it is set to an empty string. +* **backend_exclusions** - Optional - Space separated list of backend files or directories to **exclude** when checking for changes. Globs are supported. By default, it is set to an empty string. +* **frontend_directories** - Optional - Space separated list of frontend directories to check for changes. By default, it is set to an empty string +* **frontend_exclusions** - Optional - Space separated list of frontend files or directories to **exclude** when checking for changes. Globs are supported. By default, it is set to an empty string. +* **ubuntu_version** - Optional - The Ubuntu version to run the workflow against. By default, it is set to `latest`. + +#### Outputs + +* **backend** - The number of backend files that have changed. +* **frontend** - The number of frontend files that have changed. + +## [Reusable node tests workflow](_node.yml) + +This sub workflow install node dependencies and run frontend linters and tests. + +It is composed of nine steps: + +1. **Check out latest commit for current branch** - This step checks out the latest commit for the current branch of the repository. To do so, it uses GitHub's [**checkout**](https://github.com/actions/checkout) action with no parameters. +2. **Set up Node.js** - This step sets Node.js up downloading binaries and project's dependencies. This is done using the GitHub's [**setup-node**](https://github.com/actions/setup-node) action which also allows to cache and restore the project dependencies. It's used with the following parameters: + 1. **node-version** - Node.js version to use - It is set according to *node_version* input variable. + 2. **cache** - Which package manager used to install and cache packages - It is set to `npm`. + 3. **cache-dependency-path** - Path to the dependency file: `package-lock.json`, `yarn.lock` etc. It is set to `/package-lock.json`, where *working_directory* is the input variable. +3. **Add dependencies** - This step adds additional dependencies to the `package-lock.json` file. Specifically, these packages are added to the **devDependencies** part of the aforementioned file. Which packages will be added is chosen accordingly to input variables: + 1. *use_jest* + 2. *use_react* + 3. *use_eslint* + 4. *use_prettier* + 5. *use_stylelint* +4. **Install packages** - This step install all missing packages from the dependency file in the directory specified by the *working_directory* input variable. +5. **Run linters** - This step uses [**node_linter**](../actions/node_linter/action.yml) action to run linters against the frontend source code. +6. **Check packages licenses** - This step uses [**pilosus/action-pip-license-checker**](https://github.com/pilosus/action-pip-license-checker) to check the licenses used by the project requirements. +7. **Run CodeQL** - This step uses [**codeql**](../actions/codeql/action.yml) action to run CodeQL to discover vulnerabilities across the codebase. +8. **Run custom command** - This step is performed only if the input variable *custom_command* is not empty. The step simply run the bash command described in the previously mentioned input variable in the working directory specified by the *working_directory* input variable. +9. **Run jest tests** - This step runs Jest tests if the input variable *use_jest* is set to true. Finally, if *use_coverage* and *upload_coverage* are set to true, a coverage report is generated and uploaded. + +### Documentation + +#### Inputs + +* **node_versions** - Required - An array of Node.js versions to use. +* **working_directory** - Required - Path to the `package.json` file +* **check_packages_licenses** - Optional - Whether to check npm packages licenses or not. By default it is set to true. +* **use_jest** - Optional - Whether to use Jest test suite or not. By default it is set to false. +* **use_react** - Optional - Whether react is used by the project or not. By default it is set to false. +* **use_eslint** - Optional - Whether to use ESlint linter or not. By default it is set to true +* **use_prettier** - Optional - Whether to use Prettier formatter or not. By default it is set to true. +* **use_stylelint** - Optional - Whether to use Stylelint linter or not. By default it is set to true. +* **use_coverage** - Optional - Whether to use Coverage or not. To work, it also require *use_jest* to be true. By default it is set to false. +* **upload_coverage** - Optional - Whether to upload coverage report to GitHub. By default it is set to false +* **run_codeql** - Optional - Whether to run CodeQL against the codebase. By default it is set to false. +* **custom_command** - Optional - A custom bash command to be run by the workflow. By default it is set to an empty string. +* **max_timeout** - Optional - A maximum amount of minutes allowed for the workflow to run. By default it is set to 30. +* **ubuntu_version** - Optional - The Ubuntu version to run the workflow against. By default it is set to `latest`. + +## [Reusable python linter workflow](_python.yml) + +This sub workflow runs Python linters and tests against the codebase. + +It is composed of one job: + +1. **python** - This job is composed of thirty-one steps: + 1. **Check out latest commit** - Checks out the latest commit on the current branch of the repository using the GitHub's [**checkout**](https://github.com/actions/checkout) action. + 2. **Set up Python** - Sets up Python on the runner machine using GitHub's [**setup-python**](https://github.com/actions/setup-python) action with the following parameter: + 1. **python-version** - Which Python version to use - It is set according to the *python_versions* input variable. + 3. **Inject stuff to environment** - This step adds a few environment variables to the system's environment. Specifically: + 1. If *django_settings_module* is set, **PYTHONPATH** and **DJANGO_SETTINGS_MODULE** will be added to the runner's environment. + 2. If *run_codeql* is true, **CODEQL_PYTHON** will be added to the runner's environment. + 4. **Restore APT cache related to PR event** - This step will try to restore the APT cache related to the PR event using [**restore_apt_cache**](../actions/apt_requirements/restore_apt_cache/README.md) with the following parameter: + 1. **apt_requirements_file_path** - Path to the APT requirements file - It is set to the *packages_path* input variable. + 5. **Restore APT cache related to target branch** - This step will try to restore the APT cache related related to the target branch (of the PR) using [**restore_apt_cache**](../actions/apt_requirements/restore_apt_cache/README.md) only if **Restore APT cache related to PR event** produces a cache miss. It is run with the following parameter: + 1. **apt_requirements_file_path** - Path to the APT requirements file - It is set to the *packages_path* input variable. + 2. **git_reference** - A git reference (name of the branch, reference to the PR) that will be used to build the cache key - It is set to the target branch. + 6. **Restore APT repositories** - If both PR event and target branch APT cache restore attempt resulted in a cache miss, the APT repositories list is refreshed using `sudo apt-get update`. + 7. **Install APT requirements** - This step installs APT requirements listed in the *packages_path* requirements file. **Since they are not required, recommended packages are not downloaded**. + 8. **Save APT cache related to PR event** - When the attempt to restore the APT cache related to the PR event results in a cache miss, the newly populated APT cache is saved to GitHub. This is performed using [**save_apt_cache**](../actions/apt_requirements/save_apt_cache/README.md) action with the following parameter: + 1. **apt_requirements_file_path** - Path to the APT requirements file - It is se to the *packages_path* input variable. + 9. **Create linter requirements file** - This step creates the linter requirements file using the [**create_linter_requirements_file**](../actions/python_requirements/create_linter_requirements_file/README.md) action. + 10. **Create dev requirements file** - This step creates the development requirements file using the [**create_dev_requirements_file**](../actions/python_requirements/create_dev_requirements_file/README.md) action. + 11. **Create docs requirement file** - This step creates the documentation requirements file using the [**create_docs_requirements_file**](../actions/python_requirements/create_docs_requirements_file/README.md) action. + 12. **Restore Python virtual environment related to PR event** - This step attempts to restore the Python virtual environment for the PR using the [**restore_python_virtualenv**](../actions/python_requirements/restore_virtualenv/README.md) action. + 13. **Restore Python virtual environment related to target branch** - If the attempt to restore the Python virtual environment for the PR, result in a cache miss, an attempt to restore the Python virtual environment for the target branch is made using the [**restore_python_virtualenv**](../actions/python_requirements/restore_virtualenv/README.md) action. + 14. **Create Python virtual environment** - If both attempts to restore the Python virtual environment for the PR, for the target branch, result in a cache miss, a Python virtual environment is created using the [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action. + 15. **Restore pip cache related to PR event** - If both attempts to restore the Python virtual environment for the PR, for the target branch, result in a cache miss, an attempt to restore the pip cache for the PR event is made using the [**restore_pip_cache**](../actions/python_requirements/restore_pip_cache/README.md) action. + 16. **Restore pip cache related to target branch** - If both attempts to restore the Python virtual environment for the PR, for the target branch, as well as the pip cache for the PR, result in a cache miss, an attempt to restore the pip cache for the target branch is made using the [**restore_pip_cache**](../actions/python_requirements/restore_pip_cache/README.md) action. + 17. **Install project requirements** - If both attempts to restore the Python virtual environment for the PR event, and the target branch result in a cache miss, project requirements are installed from the working directory specified by the *install_from* input variable. + 18. **Install other requirements** - If the attempt to restore the Python virtual environment for the PR event result in a cache miss, developer, linters and documentation requirements are installed from the working directory specified by *working_directory* input variable. + 19. **Check requirements licenses** - If the input variable *check_requirements_licenses* is set to true and the attempt to restore the Python virtual environment related to the PR event result in a cache miss, this step performs the requirements licenses check using [**pilosus/action-pip-license-checker**](https://github.com/pilosus/action-pip-license-checker). + 20. **Print wrong licenses** - If the output of **Check requirements licenses** is `failure`, the list of licenses for which the check failed will be returned. + 21. **Save Python virtual environment related to PR event** - If the attempt to restore the Python virtual environment resulted in a cache miss, the Python virtual environment is saved for the PR event using the [*save_virtualenv*](../actions/python_requirements/save_virtualenv/README.md) action with the following parameter: + 1. **requirements_paths** - A space separated list of requirements file paths - It is set to the combination of *requirements_path*, `requirements-linters.txt`, `requirements-dev.txt` and `requirements-docs.txt` joined by spaces. + 22. **Save pip cache related to PR event** - If both attempts to restore the Python virtual environment and the pip cache related to the PR resulted in a cache miss, the pip cache is saved for the PR event using the [*save_pip_cache*](../actions/python_requirements/save_pip_cache/README.md) action. + 23. **Run linters** - If one of the following input variables: *use_black*, *use_isort*, *use_flake8*, *use_pylint*, *use_bandit* and *use_autoflake* is true, this step executes the linters against the codebase in the working directory specified by the *working_directory* variable. + 24. **Run CodeQL** - If the *run_codeql* input variable is true, this step runs CodeQL against the codebase using the [**codeql**](../actions/codeql/action.yml) action in the working directory specified by the *working_directory* variable. + 25. **Build Docs** - If the *check_docs_directory* input variable is set, this step executes `rstcheck` to ensure that the documentation in *check_docs_directory* is valid. Finally, the documentation is built using `sphinx`. + 26. **Start services** - If one or more of the following input variables: *use_postgres*, *use_elastic_search*, *use_memcached*, *use_redis*, *use_rabbitmq* and *use_mongo* are true, this step creates the Docker container for the service using the [**services**](../actions/services/action.yml) action. Additional parameters, such as *postgres_db* or *elasticsearch_version* can also be provided to the aforementioned action. + 27. **Start celery worker** - If the *use_celery* input variable is true, a Celery worker is created for the *celery_app* application. The `celery` command is executed in the working directory specified by the *working_directory* input variable. + 28. **Run custom command** - If the *custom_command* input variable is not empty, the command defined by the variable is executed in the working directory specified by the *working_directory* input variable. + 29. **Check migrations** - If *check_migrations* is true and *django_settings_module* is not empty, this step will perform a dry run of `django-admin makemigrations` to ensure that the migrations are valid. + 30. **Run unittest** - This step runs Python tests against the codebase in the directory described by the *working_directory* input variable. Additionally, according to *tags_for_manual_tests* and *tags_for_slow_tests* variables, some tests will be excluded from the run. + 31. **Create coverage output** - If *use_coverage* and *upload_coverage* are set to true, this step produces a coverage report of the codebase and uploads it to GitHub. The *working_directory* input variable is used to determines the directory in which coverage should be run. + +### Documentation + +#### Inputs + +* **python_versions** - Required - Python versions used by this workflow in the form of a JSON array. +* **ubuntu_version** - Optional - Ubuntu version to run workflow against. By default, it is set to `latest`. +* **working_directory** - Required - Directory in which to run linters. +* **requirements_path** - Required - Path to the requirements file of the Python project. +* **install_from** - Optional - Directory where all installation commands will be run. By default, it is set to `.`. +* **packages_path** - Optional - Path to the APT requirements file of the Python project. By default, it is set to an empty string. +* **env** - Optional - A JSON object containing a set of environment variables to be added to the system's environment. By default, it is set to an empty JSON object `{}`. +* **max_timeout** - Optional - Maximum amount of time (in minutes) the workflow is allowed to run. By default, it is set to `30`. +* **use_black** - Optional - Whether to use black formatter. By default, it is set to `false`. +* **use_isort** - Optional - Whether to use isort formatter. By default, it is set to `false`. +* **use_autoflake** - Optional - Whether to use autoflake linter. By default, it is set to `false`. +* **use_bandit** - Optional - Whether to use bandit linter. By default, it is set to `false`. +* **use_flake8** - Optional - Whether to use flake8 linter. By default, it is set to `false`. +* **use_pylint** - Optional - Whether to use pylint linter. By default, it is set to `false`. +* **use_coverage** - Optional - Whether to use coverage. By default, it is set to `false`. +* **coverage_config_path** - Optional - Path to the coverage configuration file. By default, it is set to `.coveragerc`. +* **upload_coverage** - Optional - Whether to upload coverage report to GitHub. To work, it needs *use_coverage* to be true. By default, it is set to `false`. +* **run_codeql** - Optional - Whether to run CodeQL against codebase. By default, it is set to `false`. +* **use_celery** - Optional - Whether to create a Celery container. By default, it is set to `false`. +* **use_elastic_search** - Optional - Whether to create an Elasticsearch container. By default, it is set to `false`. +* **use_memcached** - Optional - Whether to create a Memcached container. By default, it is set to `false`. +* **use_mongo** - Optional - Whether to create a MongoDB container. By default, it is set to `false`. +* **use_postgres** - Optional - Whether to create a PostgresDB container. By default, it is set to `false`. +* **use_rabbitmq** - Optional - Whether to create a RabbitMQ container. By default, it is set to `false`. +* **use_redis** - Optional - Whether to create a Redis container. By default, it is set to `false`. +* **celery_app** - Optional - A Celery application name. Requires *use_celery* to be true. By default, it is set to an empty string. +* **celery_queues** - Optional - A comma separated list of Celery queues. Requires *use_celery* to be true. By default, it is set to `default`. +* **elasticsearch_version** - Optional - Elasticsearch's container version. By default, it is set to `latest`. +* **elasticsearch_port** - Optional - Elasticsearch's container exposed port. By default, it is set to `9200`. +* **memcached_version** - Optional - Mecached's container version. By default, it is set to `latest`. +* **mongo_version** - Optional - MongoDB's container version. By default, it is set to `latest`. +* **postgres_db** - Optional - PostgresDB database name. Requires *use_postgres* to be true. By default, it is set to `db`. +* **postgres_user** - Optional - PostgresDB user name. Requires *use_postgres* to be true. By default, it is set to `user`. +* **postgres_password** - Optional - PostgresDB password. Requires *use_postgres* to be true. By default, it is set to `password`. +* **postgres_version** - Optional - PostgresDB's container version. Requires *use_postgres* to be true. By default, it is set to `latest`. +* **rabbitmq_version** - Optional - RabbitMQ's container version. Requires *use_rabbitmq* to be true. By default, it is set to `latest`. +* **redis_version** - Optional - Redis' container version. Requires *use_redis* to be true. By default, it is set to `latest`. +* **django_settings_module** - Optional - Path to the Django settings file. By default, it is set to an empty string. +* **check_migrations** - Optional - Whether to check that the project's migrations are valid. Requires *django_settings_module* to be set. By default, it is set to `false`. +* **check_requirements_licenses** - Optional - Whether to check that the requirements license is valid. Requires *django_settings_module* to be set. By default, it is set to `true`. +* **ignore_requirements_licenses_regex** - Optional - A regex that describes which directories should be ignored when checking the validity of requirements licenses. By default, it is set to `uWSGI.*|lunardate.*|.*QuokkaClient.*|pyquokka.*`. +* **tags_for_slow_tests** - Optional - A space separated list of tags for tests that will only be run on the master/main branch. **Works only for Django projects**. By default, it is set to an `slow`. +* **tags_for_manual_tests** - Optional - A space separated list of tags for tests that will only be run **manually** (CI will ignore them). **Works only for Django projects**. By default, it is set to `manual`. +* **custom_command** - Optional - A custom bash command to run. By default, it is set to an empty string. +* **check_docs_directory** - Optional - Path to the documentation directory in which `rstcheck` will be run to check documentation files. By default, it is set to an empty string. +* **check_dockerfile** - Optional - Path to a Dockerfile to be checked. **Warning: if set it may significantly increase the action time**. By default, it is set to an empty string. + +## [Create APT cache](create_apt_cache.yaml) + +This workflow is run in the event of **a push on branches *main*, *master*, *develop*, *dev***. Specifically, it is triggered only when the APT requirements file is updated. + +The workflow is composed of a single job: + +1. **Create cache for APT dependencies** - This job, as described by its name, creates a cache for APT dependencies and stores it on GitHub. It is composed of four steps: + 1. **Check out latest commit on current branch** - This step checks out the latest commit on the current branch of the repository. + 2. **Install APT dependencies** - This step refreshes APT repositories and then install the project dependecies. This action is required to produce the APT cache that will be saved later. + 3. **Save APT cache** - This step saves APT cache on GitHub. The GitHub's [**save_apt_cache**](../actions/apt_requirements/save_apt_cache/README.md) action is used. + +## [Create Python cache](create_python_cache.yaml) + +This workflow is run in the event of **a push on branches *main*, *master*, *develop*, *dev***. Specifically, it is triggered only when the Python requirements file is updated. + +The workflow is composed of a single job: + +1. **Create cache for Python dependencies** - This job, as described by its name, creates a cache for Python dependencies and stores it on GitHub. It is composed of four steps: + 1. **Check out latest commit** - This step checks out the latest commit on the current branch for the repository. + 2. **Set up Python** - This step install Python on the runner. + 3. **Set up Python virtual environment** - This step uses [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action to create a Python virtual environment. + 4. **Install Python dependencies** - This step install Python requirements to produce the final virtual environment that will be cached. Also, installing the Python dependencies, creates the pip cache. + 5. **Save pip cache** - This step uses [**save_pip_cache**](../actions/python_requirements/save_pip_cache/README.md) action to save pip's download cache on GitHub. + 6. **Create virtual environment cache** - This step uses [**save_virtualenv**](../actions/python_requirements/save_virtualenv/README.md) action to save virtual environment on GitHub's cache. + +## [CI](pull_request_automation.yml) + +This workflow runs in the case of a **pull request on branches *master*, *main*, *develop*, *dev*** and it's the core CI workflow. + +It is composed of three jobs: + +1. **detect-changes** - This job detects and enumerates changes to backend and/or frontend files. To do so, it uses the [**_detect_changes**](_detect_changes.yml) workflow. +2. **node** - If any changes to the frontend files are found, [**_node**](_node.yml) workflow is run. +3. **python** - If any changes to the backend files are found, [**_python**](_python.yml) workflow is run. + +## [Release and publish](release.yml) + +TODO + +## [Reusable release and tag workflow](_release_and_tag.yml) + +TODO diff --git a/.github/workflows/_detect_changes.yml b/.github/workflows/_detect_changes.yml index eb68be3..9e9b8a6 100644 --- a/.github/workflows/_detect_changes.yml +++ b/.github/workflows/_detect_changes.yml @@ -3,22 +3,22 @@ on: workflow_call: inputs: backend_directories: - description: Backend directories separated by spaces + description: Space separated list of backend directories required: false type: string backend_exclusions: - description: Backend directories or files to be excluded separated by spaces + description: Space separated list of Backend directories or files to be excluded required: false type: string frontend_directories: - description: Frontend directories separated by spaces + description: Space separated list of frontend directories required: false type: string frontend_exclusions: - description: Frontend directories or files to be excluded separated by spaces + description: Space separated list of frontend directories or files to be excluded required: false type: string @@ -45,13 +45,16 @@ jobs: backend: ${{steps.diff_check_backend.outputs.backend}} frontend: ${{steps.diff_check_frontend.outputs.frontend}} steps: - - uses: actions/checkout@v4 + - name: Check out PR target branch + uses: actions/checkout@v4 with: ref: ${{ github.base_ref }} - - uses: actions/checkout@v4 + - name: Check out source branch latest commit + uses: actions/checkout@v4 with: clean: false + - name: Generate summary if: ${{inputs.backend_directories != ''}} | ${{inputs.frontend_directories != ''}} run: | @@ -76,7 +79,6 @@ jobs: echo "::debug::diff command results: $(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS | head -n -1 )" echo "backend $BACKEND_CHANGES" - - name: Generate diffs for frontend if: ${{inputs.frontend_directories != ''}} id: diff_check_frontend diff --git a/.github/workflows/_node.yml b/.github/workflows/_node.yml index 1a850b0..074bbe1 100644 --- a/.github/workflows/_node.yml +++ b/.github/workflows/_node.yml @@ -88,7 +88,8 @@ jobs: node_version: ${{ fromJson(inputs.node_versions) }} language: ['javascript'] steps: - - uses: actions/checkout@v4 + - name: Check out latest commit for current branch + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index 1f6624f..e2142b1 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -245,7 +245,8 @@ jobs: language: ['python'] env: ${{ fromJson(inputs.env) }} steps: - - uses: actions/checkout@v4 + - name: Check out latest commit + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 @@ -264,33 +265,39 @@ jobs: shell: bash - - name: Install apt requirements - if: inputs.packages_path - uses: ./.github/actions/apt_requirements + - name: Restore APT cache related to PR event + id: restore_apt_cache_pr + uses: ./.github/actions/apt_requirements/restore_apt_cache with: - requirements_file: ${{ inputs.packages_path }} - - - name: Check requirements licenses - if: inputs.check_requirements_licenses && steps.cache-virtualenv.outputs.cache-hit != 'true' - id: license_check_report - continue-on-error: true - uses: pilosus/action-pip-license-checker@v2 + apt_requirements_file_path: ${{ inputs.packages_path }} + + - name: Restore APT cache related to target branch + id: restore_apt_cache_target_branch + if: steps.restore_apt_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/apt_requirements/restore_apt_cache with: - requirements: ${{ inputs.install_from }}/${{ inputs.requirements_path }} - exclude: ${{ inputs.ignore_requirements_licenses_regex }} - headers: true - fail: 'StrongCopyleft,NetworkCopyleft,Error' - fails-only: true + apt_requirements_file_path: ${{ inputs.packages_path }} + git_reference: ${{ github.base_ref }} + + - name: Refresh APT repositories + if: > + steps.restore_apt_cache_pr.outputs.cache-hit != 'true' && + steps.restore_apt_cache_target_branch.outputs.cache-hit != 'true' + run: | + sudo apt-get update + shell: bash - - name: Print wrong licenses - if: steps.license_check_report.outcome == 'failure' + - name: Install APT requirements run: | - echo "License check failed" - echo "====================" - echo "${{ steps.license_check_report.outputs.report }}" - echo "====================" - exit 1 + sudo apt-get install -y --no-install-recommends $(tr '\n' ' ' < ${{ inputs.packages_path }}) shell: bash + + - name: Save APT cache related to PR event + if: > + steps.restore_apt_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/apt_requirements/save_apt_cache + with: + apt_requirements_file_path: ${{ inputs.packages_path }} - name: Create linter requirements file uses: ./.github/actions/python_requirements/create_linter_requirements_file @@ -319,7 +326,7 @@ jobs: id: restore_python_virtual_environment_pr uses: ./.github/actions/python_requirements/restore_virtualenv/ with: - requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" + requirements_paths: "${{ inputs.requirements_path }} requirements-linters.txt requirements-dev.txt requirements-docs.txt" - name: Restore Python virtual environment related to target branch id: restore_python_virtual_environment_target_branch @@ -370,14 +377,38 @@ jobs: shell: bash working-directory: ${{ inputs.install_from }} - - name: Save Python virtual environment related to the PR event + - name: Check requirements licenses + if: > + inputs.check_requirements_licenses && + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' + id: license_check_report + continue-on-error: true + uses: pilosus/action-pip-license-checker@v2 + with: + requirements: ${{ inputs.install_from }}/${{ inputs.requirements_path }} + exclude: ${{ inputs.ignore_requirements_licenses_regex }} + headers: true + fail: 'StrongCopyleft,NetworkCopyleft,Error' + fails-only: true + + - name: Print wrong licenses + if: steps.license_check_report.outcome == 'failure' + run: | + echo "License check failed" + echo "====================" + echo "${{ steps.license_check_report.outputs.report }}" + echo "====================" + exit 1 + shell: bash + + - name: Save Python virtual environment related to PR event if: > steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' uses: ./.github/actions/python_requirements/save_virtualenv with: - requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" + requirements_paths: "${{ inputs.requirements_path }} requirements-linters.txt requirements-dev.txt requirements-docs.txt" - - name: Save pip cache related to the PR event + - name: Save pip cache related to PR event if: > steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && steps.restore_pip_cache_pr.outputs.cache-hit != 'true' diff --git a/.github/workflows/create_apt_cache.yaml b/.github/workflows/create_apt_cache.yaml index 06f26cc..9bd5fd7 100644 --- a/.github/workflows/create_apt_cache.yaml +++ b/.github/workflows/create_apt_cache.yaml @@ -23,7 +23,8 @@ jobs: name: Create cache for APT dependencies runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Check out latest commit on current branch + uses: actions/checkout@v4 # Remember to set the same APT requirements file path set before! - name: Install APT dependencies @@ -31,13 +32,7 @@ jobs: sudo apt-get update sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < .github/test/python_test/packages.txt) - - name: Compute apt_packages.txt SHA256 hash - id: compute_apt_packages_sha256_hash - uses: ./.github/actions/misc/compute_files_hash + - name: Save APT cache + uses: ./.github/actions/apt_requirements/save_apt_cache with: - file_paths: .github/test/python_test/packages.txt - - - uses: actions/cache/save@v4 - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.computed_hash }} + apt_requirements_file_path: .github/test/python_test/packages.txt diff --git a/.github/workflows/create_python_cache.yaml b/.github/workflows/create_python_cache.yaml index a6b65b5..cac8510 100644 --- a/.github/workflows/create_python_cache.yaml +++ b/.github/workflows/create_python_cache.yaml @@ -32,7 +32,7 @@ jobs: with: python-version: "3.12" - - name: Set up Python's virtual environment + - name: Set up Python virtual environment uses: ./.github/actions/python_requirements/create_virtualenv - name: Install Python dependencies diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ff6f6e..d8363d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Added "release.yml" action to to push containers to AWS ECR * Added *create_apt_cache.yaml* workflow to cache APT requirements each time a commit is pushed on selected branch and **when the requirements file has changed**. +* Added documentation. ### Bugfix diff --git a/actions/apt_requirements/action.yml b/actions/apt_requirements/action.yml deleted file mode 100644 index 7134837..0000000 --- a/actions/apt_requirements/action.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Composite action install APT requirements -description: Composite action to install APT requirements -inputs: - requirements_file: - description: Requirements file - required: true - -runs: - using: "composite" - steps: - - name: Compute apt requirements file SHA256 hash - id: compute_apt_requirements_file_sha256_hash - uses: ./.github/actions/misc/compute_files_hash - with: - file_paths: ${{ inputs.requirements_file }} - - # Vital to be able to restore cache - # If write permission is not set, a permissions error will be raised - - name: Modification to /var/cache/apt/archives permissions - run: | - sudo chmod a+w /var/cache/apt/archives - shell: bash - - - uses: actions/cache/restore@v4 - id: restore_cache_from_parent_branch - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.base_ref }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - - - uses: actions/cache/restore@v4 - id: restore_cache_from_current_branch - if: steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} - - - name: Refresh repositories - if: > - steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && - steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' - run: | - sudo apt-get update - shell: bash - - - name: Install requirements - run: | - sudo apt-get install -y --no-install-recommends $(tr '\n' ' ' < ${{ inputs.requirements_file }}) - shell: bash - - - uses: actions/cache/save@v4 - id: cache_apt_requirements_for_current_branch - if: > - steps.restore_cache_from_parent_branch.outputs.cache-hit != 'true' && - steps.restore_cache_from_current_branch.outputs.cache-hit != 'true' - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/actions/apt_requirements/restore_apt_cache/README.md b/actions/apt_requirements/restore_apt_cache/README.md new file mode 100644 index 0000000..046b58e --- /dev/null +++ b/actions/apt_requirements/restore_apt_cache/README.md @@ -0,0 +1,29 @@ +# Composite action restore APT cache + +This action restores an APT cache from GitHub's cache. + +Combined with [**save_apt_cache**](../save_apt_cache/README.md), it helps save time by avoiding the download of APT requirements. + +The action is composed of five steps: + +1. **Compute APT requirements files SHA256 hash** - This step uses [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) action to compute a single SHA256 hash of the APT requirements file described by the *apt_rquirements_file_path* input variable. The computed SHA256 hash will be part of the cache key. +2. **Backup `/var/cache/apt/archives permissions`** - This step backs up the permissions associated to the `/var/cache/apt/archives` directory. So, after restoring the APT cache they can be restored to the original ones. +3. **Add write permissions for all to `/var/cache/apt/archives`** - This step sets the write permission to the `/var/cache/apt/archives`. This is crucial because the [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) GitHub's action needs to be able to write to it. Without setting the correct write permission, a permission error is raised. +4. **Restore APT cache** - This step restores the APT cache. It uses the GitHub's [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action with the following parameters: + * **path** - A list of files, directories, or paths to restore - set to `/var/cache/apt/archives/*.deb`. + * **key** - An explicit key for a cache entry - set to the combination of three strings: + * *git_reference*, provided as an input to the action. + * A static part, `-apt-` + * The previously computed SHA256 hash of the APT requirements file. +5. **Restore original permissions to `/var/cache/apt/archives` and delete backup** - This step restore the original permissions to the `/var/cache/apt/archives` directory. Finally, the backup file is deleted. + +## Documentation + +### Inputs + +* **apt_requirements_file_path** - Required - Path to the APT requirements file. It will be used to compute a SHA256 hash used in the cache key. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. + +### Outputs + +* **cache-hit** - A boolean value which is true when APT cache is found in the GitHub's cache, false otherwise. diff --git a/actions/apt_requirements/restore_apt_cache/action.yml b/actions/apt_requirements/restore_apt_cache/action.yml new file mode 100644 index 0000000..282935b --- /dev/null +++ b/actions/apt_requirements/restore_apt_cache/action.yml @@ -0,0 +1,64 @@ +name: Composite action restore APT cache +description: Composite action to restore APT cache +inputs: + apt_requirements_file_path: + description: Path to the APT requirements file + required: true + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +outputs: + cache-hit: + description: Whether the APT cache was found in the GitHub's cache or not. + value: ${{ steps.restore_apt_cache.outputs.cache-hit }} + + +runs: + using: "composite" + steps: + - name: Compute APT requirements file SHA256 hash + id: compute_apt_requirements_file_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.apt_requirements_file_path }} + + - name: Backup /var/cache/apt/archives permissions + id: backup_apt_cache_dir_permissions + run: | + PERMISSIONS_FILE_PATH="/tmp/apt_cache_dir_permissions.facl" + echo "apt_cache_dir_permissions_file=$PERMISSIONS_FILE_PATH" > $GITHUB_OUTPUT + sudo getfacl -p /var/cache/apt/archives > $PERMISSIONS_FILE_PATH + ARCHIVES_PERMISSIONS=$(ls -ld /var/cache/apt/archives) + echo "::debug::Original permissions given to /var/cache/apt/archives: $ARCHIVES_PERMISSIONS" + echo "::debug::Created /var/cache/apt/archives permissions backup to $PERMISSIONS_FILE_PATH" + shell: bash + + # Vital to be able to restore cache + # If write permission is not set, a permissions error will be raised + - name: Add write permission for all to /var/cache/apt/archives + run: | + sudo chmod a+w /var/cache/apt/archives + ARCHIVES_NEW_PERMISSIONS=$(ls -ld /var/cache/apt/archives) + echo "::debug::New permissions given to /var/cache/apt/archives: $ARCHIVES_NEW_PERMISSIONS" + shell: bash + + - name: Restore APT cache + uses: actions/cache/restore@v4 + id: restore_apt_cache + with: + path: /var/cache/apt/archives/*.deb + key: ${{ inputs.git_reference }}-apt-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} + + - name: Restore original permissions to /var/cache/apt/archives and delete backup + run: | + PERMISSIONS_FILE_PATH=${{ steps.backup_apt_cache_dir_permissions.outputs.apt_cache_dir_permissions_file }} + sudo setfacl --restore="$PERMISSIONS_FILE_PATH" + ARCHIVES_RESTORED_PERMISSIONS=$(ls -ld /var/cache/apt/archives) + echo "::debug::Restored original permissions to /var/cache/apt/archives: $ARCHIVES_RESTORED_PERMISSIONS" + if [[ -f "$PERMISSIONS_FILE_PATH" ]]; then + sudo rm "$PERMISSIONS_FILE_PATH" + echo "::debug::Correctly removed $PERMISSIONS_FILE_PATH permissions backup file" + fi + shell: bash \ No newline at end of file diff --git a/actions/apt_requirements/save_apt_cache/README.md b/actions/apt_requirements/save_apt_cache/README.md new file mode 100644 index 0000000..4d8dca8 --- /dev/null +++ b/actions/apt_requirements/save_apt_cache/README.md @@ -0,0 +1,22 @@ +# Composite action save APT cache + +This action saves the APT cache, almost always located at `/var/cache/apt/archives/*.deb` to the GitHub's cache. + +Combined with [**restore_apt_cache**](../restore_apt_cache/README.md) helps save time by avoiding the download of APT requirements. + +The action is composed of two steps: + +1. **Compute APT requirements file SHA256 hash** - This step uses the [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) action to compute the SHA256 hash of the APT requriments file that will be part of the cache key. +2. **Save APT cache** - This step does the real caching on GitHub. The GitHub's [**cache/save**](https://github.com/actions/cache/blob/main/save/README.md) is used with the following parameters: + 1. **path** - A list of files, directories, or paths to cache - set to `/var/cache/apt/archives/*.deb` to save all `*.deb` files in APT cache. + 2. **key** - An explicit key for a cache entry - set to the combination of three strings: + 1. *git_reference*, provided as an input to the action. + 2. A static part, `-apt-` + 3. The previously computed SHA256 hash of the APT requirements file. + +## Documentation + +### Inputs + +* **apt_requirements_file_path** - Required - Path to the APT requirements file. It will be used to compute a SHA256 hash used in the cache key. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. diff --git a/actions/apt_requirements/save_apt_cache/action.yml b/actions/apt_requirements/save_apt_cache/action.yml new file mode 100644 index 0000000..af41cfd --- /dev/null +++ b/actions/apt_requirements/save_apt_cache/action.yml @@ -0,0 +1,24 @@ +name: Composite action save APT cache +description: Composite action to save APT cache +inputs: + apt_requirements_file_path: + description: Path to the APT requirements file + required: true + git_reference: + description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. + required: false + default: ${{ github.ref_name }} + +runs: + using: "composite" + steps: + - name: Compute APT requiremments file SHA256 hash + id: compute_apt_requirements_file_sha256_hash + uses: ./.github/actions/misc/compute_files_hash + with: + file_paths: ${{ inputs.apt_requirements_file_path }} + - name: Save APT cache + uses: actions/cache/save@v4 + with: + path: /var/cache/apt/archives/*.deb + key: ${{ inputs.git_reference }}-apt-${{ steps.compute_apt_requirements_file_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/actions/misc/compute_files_hash/README.md b/actions/misc/compute_files_hash/README.md new file mode 100644 index 0000000..f1c594f --- /dev/null +++ b/actions/misc/compute_files_hash/README.md @@ -0,0 +1,18 @@ +# Composite action compute files hash + +This action computes a single SHA256 hash of one or more files. +Given a **space separated list of file paths**, a new file is created by concatenating all those files together. Then the SHA256 hash of the newly created file is computed and returned as the output. + +Before being joined together, each file is tested to ensure that it **exists** and that it is **a regular file**. + +This action is useful when saving/restoring a cache in which a unique key is required. As a matter of fact, the hash is used as a part of the hash key. + +## Documentation + +### Inputs + +* `file_paths` - Mandatory - Space separated list of file paths for which a single SHA256 hash will be computed. + +### Outputs + +* `computed_hash` - A SHA256 hash of the file obtained by joining (concatenating) all input files together. diff --git a/actions/misc/compute_files_hash/action.yml b/actions/misc/compute_files_hash/action.yml index 2c3b905..fca2a53 100644 --- a/actions/misc/compute_files_hash/action.yml +++ b/actions/misc/compute_files_hash/action.yml @@ -2,8 +2,8 @@ name: Composite action compute files hash description: Composite action to compute a single hash of one or more files inputs: file_paths: - description: Comma separeted list of files. - required: false + description: Space separeted list of files for which a single SHA256 hash will be computed. + required: true outputs: computed_hash: @@ -16,11 +16,13 @@ runs: - name: Compute files SHA256 hash id: compute_files_sha256_hash run: | + if [[ -z '${{ inputs.file_paths }}' ]]; then + echo "::error::file_paths cannot be empty!" + exit 1 + fi JOINED_FILES="cat " # Create a bash array of file paths - IFS=',' read -r -a files <<< "${{ inputs.file_paths }}" - echo "::debug::File paths array is composed by: ${files[@]}" - for file in ${files[@]}; + for file in ${{ inputs.file_paths }}; do if [[ -f $file ]]; then # Concat file path to cat command diff --git a/actions/python_requirements/create_dev_requirements_file/README.md b/actions/python_requirements/create_dev_requirements_file/README.md new file mode 100644 index 0000000..ae32be0 --- /dev/null +++ b/actions/python_requirements/create_dev_requirements_file/README.md @@ -0,0 +1,13 @@ +# Composite action create Python dev requirements file + +This action creates the `requirements-dev.txt` file which will contain all **development dependencies**. + +As of today, the only development dependency supported is `coverage`. + +## Documentation + +### Inputs + +* **install_from** - Optional - The path used as working directory when creating the `requirements-dev.txt` file. It defaults to the current directory (i.e. `.`). +* **project_dev_requirements_file** - Optional - The path of a project `requirements-dev.txt`. This was designed in case development requirements other than coverage are required. If specified, the dependencies in the project `requirements-dev.txt` will be appended in the newly created `requirements-dev.txt`. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no custom `requirements-dev.txt`**. +* **use_coverage** - Optional - Whether to use coverage or not. It defaults to false. diff --git a/actions/python_requirements/create_docs_requirements_file/README.md b/actions/python_requirements/create_docs_requirements_file/README.md new file mode 100644 index 0000000..913192f --- /dev/null +++ b/actions/python_requirements/create_docs_requirements_file/README.md @@ -0,0 +1,12 @@ +# Composite action create Python docs requirements file + +This action creates the `requirements-docs.txt` file. This is a Python requirements file that will contain all **dependencies required to build the documentation**. + +## Documentation + +### Inputs + +* **install_from** - Optional - The path used as working directory when creating the `requirements-docs.txt` file. It defaults to the current directory (i.e. `.`). +* **project_docs_requirements_file** - Optional - The path of a project `requirements-docs.txt`. This was designed in case requirements to build documentation other than rstcheck, sphinx, sphinx_rtd_theme, sphinxcontrib-spelling and sphinxcontrib-django2 are required. If specified, the dependencies in the project `requirements-docs.txt` will be appended in the newly created `requirements-docs.txt`. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no custom `requirements-docs.txt`**. +* **django_settings_module** - Optional - Path to the Django settings file. It's used to make GitHub action aware of Django presence. In this case, `sphinxcontrib-django2` is also added to the newly created requirement file. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no Django settings file**. +* **check_docs_directory** - Optional - Path that will be used by rstcheck to check documentation. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **documentation won't be checked**. diff --git a/actions/python_requirements/create_linter_requirements_file/README.md b/actions/python_requirements/create_linter_requirements_file/README.md new file mode 100644 index 0000000..9be5aa9 --- /dev/null +++ b/actions/python_requirements/create_linter_requirements_file/README.md @@ -0,0 +1,27 @@ +# Composite action create Python linter requirements file + +This action creates the `requirements-linters.txt` file which will contain all **linter dependencies** required by the CI. +The user can then choose which linters will be run, and hence written to the `requirements-linters.txt`, by the CI by setting some flags to true like *use_black*. + +As of today only the following linters are supported: + +* `autoflake` +* `bandit` +* `black` +* `flake8` +* `flake8-django` +* `isort` +* `pylint` +* `pylint-django` + +## Documentation + +### Inputs + +* **install_from** - Optional - The path used as working directory when creating the `requirements-linters.txt` file. It defaults to the current directory (i.e. `.`). +* `project_linter_requirements_file` - Optional - The path of a project `requirements-linters.txt`. This was designed in case requirements for linters other than `autoflake`, `bandit`, `black`, `flake8`, `flake8-django`, `isort`, `pylint` and `pylint-django` are required. If specified, the dependencies in the project `requirements-linters.txt` will be appended in the newly created `requirements-linters.txt`. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no custom `requirements-linters.txt`**. +* **django_settings_module** - Optional - Path to the Django settings file. It's used to make GitHub action aware of Django presence. In the case of a Django project, `flake8-django` and `pylint-django`, may be used and hence they will be added to the newly created requirements file. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no Django settings file**. +* **use_autoflake** - Optional - Flag to state whether to use or not `autoflake` linter. It defaults to false. +* **use_bandit** - Optional - Flag to state whether to use or not `bandit` linter. It defaults to false. +* **use_flake8** - Optional - Flag to state whether to use or not `flake8` linter. It defaults to false. +* **use_pylint** - Optional - Flag to state whether to use or not `pylint` linter. It defaults to false. diff --git a/actions/python_requirements/create_virtualenv/README.md b/actions/python_requirements/create_virtualenv/README.md new file mode 100644 index 0000000..8f3361a --- /dev/null +++ b/actions/python_requirements/create_virtualenv/README.md @@ -0,0 +1,20 @@ +# Composite action create Python virtual environment + +This GitHub action creates a Python virtual environment using Python's `venv` module. + +When the *activate_only* flag set is to true, the virtual environment at *virtualenv_path* will only be activated—**no creation will take place**. + +NOTE: + +To activate a Python virtual environment, the `activate` script is often used. +However, in a GitHub Action environment, this is not enough because environment variables are "lost" at the end of the Action. For this we need to do two things: + +1. Append the `VIRTUAL_ENV` environment variable to the `GITHUB_ENV` environment file. The [`GITHUB_ENV`](https://docs.github.com/en/enterprise-cloud@latest/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-environment-variable) files makes environment variables available to any subsequent steps in a workflow job. Finally, it's important to note that `VIRTUAL_ENV` variable is created by the `activate` script and contains the path to the virtual environment. +2. Prepend the virtual environment's `bin` path to the system PATH. To allow also any subsequent steps in a workflow to be able to use it, [`GITHUB_PATH`](https://docs.github.com/en/enterprise-cloud@latest/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-system-path) is employed. + +## Documentation + +### Inputs + +* **virtualenv_path** - Optional - The path where the virtual environment will be created. It defaults to `.venv`. +* **activate_only** - Optional - Flag that states whether to only activate the virtual environment. If false, a new virtual environment will be created before being activated. It defaults to false. \ No newline at end of file diff --git a/actions/python_requirements/create_virtualenv/action.yml b/actions/python_requirements/create_virtualenv/action.yml index 00a40a4..02dcb93 100644 --- a/actions/python_requirements/create_virtualenv/action.yml +++ b/actions/python_requirements/create_virtualenv/action.yml @@ -22,5 +22,7 @@ runs: run: | source ${{ inputs.virtualenv_path }}/bin/activate echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV + echo "::debug::Virtual environment path is $VIRTUAL_ENV" echo "$VIRTUAL_ENV/bin" >> $GITHUB_PATH + echo "::debug::PATH environment variable state after $VIRTUAL_ENV/bin path being added to it: $GITHUB_PATH" shell: bash diff --git a/actions/python_requirements/restore_pip_cache/README.md b/actions/python_requirements/restore_pip_cache/README.md new file mode 100644 index 0000000..92a2a2f --- /dev/null +++ b/actions/python_requirements/restore_pip_cache/README.md @@ -0,0 +1,41 @@ +# Composite action restore pip cache + +This action restores the pip download cache from GitHub's cache. + +The action is composed of four steps: + +1. **Generate random UUID** - This step computes a random UUID, using the shell command `uuidgen`, which will be part of the cache key. Since pip cache will always be restored when a virtual environment is not found on GitHub's cache, a random UUID is required to generate a cache miss. +2. **Get pip cache directory** - This step retrieves the path to the pip cache. If *custom_pip_cache_path* is not an empty string, it will be used as pip cache path. Otherwise, the pip cache will be computed using `pip cache dir`. +3. **Restore pip cache** - This step performs the heavy lifting of the restoring. Using GitHub's [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action, the cache is restored using a **partial match**. This is performed by setting the following [inputs](https://github.com/actions/cache/tree/main/restore#inputs): + 1. **key** - an explicit key for a cache entry - will be set to a random UUID which will always trigger a cache miss. + 2. **path** - a list of files, directories, paths to restore - will be set to the pip download cache path. + 3. **restore-keys** - an ordered list of prefix-matched keys to use for restoring stale cache if no cache hit occurred for key - will be set to `-pip-cache-` to restore the most recent pip cache for the chosen git reference. +4. **Explain cache output** - This step analyze the results of the [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action and sets *real_cache_hit* environment variable to true if there was a match, false otherwise. This is necessary because, in the case of a **partial match**, the *cache-hit*, output of [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md), will be false. Instead, we use the `cache-matched-key`, another output of [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md), which contains a reference for both **partial** and full matches, but will be empty in the case of a cache miss. + +NOTE: + +This action, despite seeming a bit unusual, is correct because GitHub does not allow cache updates or overwrites. + +Let's think about a real-world scenario: + +A user updates the requirements file. + +In this case our query to GitHub's cache for the previously cached virtual environment will **always** miss. This happens because changing the requirements file results in a new SHA256 hash, so the cache key changes. + +Thus, we aim to restore the pip cache to at least *mitigate* the impact of the changes in the requirements. Specifically, we want to save time by avoiding the download of packages that did not change. + +Next, we try to query the GitHub's cache for the previously cached pip cache. However, there are a few issues: + +1. We cannot use the SHA256 of the requirements file because it has changed, leading to cache misses. +2. We cannot create a cache key without a random component because, as said earlier, GitHub does not allow overwriting or updating of a cache item. For example, a cache key like `develop-pip-cache-` would generate an error when attempting to save a new cache if one already exists with the same name. + +## Documentation + +### Inputs + +* **custom_pip_cache** - Optional - Path to the pip cache. It can be used for setting a custom pip cache path. It defaults to an empty string. In this case, the pip cache path will be computed using `pip cache dir`. More information regarding the previous command is available [here](https://pip.pypa.io/en/stable/cli/pip_cache/#description) +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. + +### Outputs + +* **cache-hit** - A boolean value which states whether pip cache was found on GitHub's cache or not. diff --git a/actions/python_requirements/restore_pip_cache/action.yml b/actions/python_requirements/restore_pip_cache/action.yml index 0c4f93b..e4568f7 100644 --- a/actions/python_requirements/restore_pip_cache/action.yml +++ b/actions/python_requirements/restore_pip_cache/action.yml @@ -1,5 +1,5 @@ -name: Composite action restore pip's cache -description: Composite action to restore pip's cache +name: Composite action restore pip cache +description: Composite action to restore pip cache inputs: custom_pip_cache_path: description: Path to pip cache. @@ -32,6 +32,7 @@ runs: else echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT fi + echo "::debug::Pip cache path $pip_cache_path" shell: bash - name: Restore pip cache id: restore_pip_cache diff --git a/actions/python_requirements/restore_virtualenv/README.md b/actions/python_requirements/restore_virtualenv/README.md new file mode 100644 index 0000000..e40a3c1 --- /dev/null +++ b/actions/python_requirements/restore_virtualenv/README.md @@ -0,0 +1,30 @@ +# Composite action restore Python virtual environment + +This action restores a Python virtual environment from GitHub's cache. + +Combined with [**save_virtualenv**](../save_virtualenv/README.md), **it helps save time by avoiding the installation of Python requirements**. + +The action is composed of three steps: + +1. **Compute requirements files SHA256 hash** - This step uses [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) action to compute a single SHA256 hash of the files described by the *requirements_paths*. The computed SHA256 hash will be part of the cache key. +2. **Restore virtual environment** - This step does the heavy lifting of restoring the virtual environment from GitHub's cache. It uses the GitHub's [**cache/restore**](https://github.com/actions/cache/blob/main/restore/README.md) action with the following parameters: + * **path** - A list of files, directories, or paths to restore - set to the virtual environment path input variable *virtual_environment_path*. + * **key** - An explicit key for a cache entry - set to the combination of three strings: + * *git_reference*, provided as an input to the action. + * A static part, `-venv-` + * The previously computed SHA256 hash of the requirements files. +3. **Activate restored virtual environment** - If the Python virtual environment was found in the GitHub's cache, it needs to be activated. This is performed using [**python_requirements/create_virtualenv**](../create_virtualenv/README.md) action with the following parameters: + * **virtualenv_path** - set to the Python virtual environment path. + * **activate_only** - set to true because it doesn't need to be created. + +## Documentation + +### Inputs + +* **virtual_environment_path** - Optional - Path where the virtual environment is located. It may be used to provide a custom path for the virtual environment. It defaults to `.venv`. +* **requirements_paths** - Required - A space separated list of requirements file paths. They will be used to compute a SHA256 hash used in the cache key. It defaults to an empty string. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. + +### Outputs + +* **cache-hit** - A boolean value which is true when virtual environment is found in the GitHub's cache, false otherwise. diff --git a/actions/python_requirements/restore_virtualenv/action.yml b/actions/python_requirements/restore_virtualenv/action.yml index 1798a87..cd76c98 100644 --- a/actions/python_requirements/restore_virtualenv/action.yml +++ b/actions/python_requirements/restore_virtualenv/action.yml @@ -6,8 +6,8 @@ inputs: required: false default: ".venv" requirements_paths: - description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. - required: false + description: Space separeted list of requirement files. They will be used to compute the hash for the cache key. + required: true git_reference: description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. required: false @@ -32,7 +32,7 @@ runs: uses: actions/cache/restore@v4 with: path: ${{ inputs.virtual_environment_path }} - key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} + key: ${{ inputs.git_reference }}-venv-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} - name: Activate restored virtual environment if: > diff --git a/actions/python_requirements/save_pip_cache/README.md b/actions/python_requirements/save_pip_cache/README.md new file mode 100644 index 0000000..e3950a0 --- /dev/null +++ b/actions/python_requirements/save_pip_cache/README.md @@ -0,0 +1,22 @@ +# Composite action save pip cache + +This action saves the pip download cache. + +Every time a user runs `pip install `, pip downloads the package and all its dependencies.The packages are saved in a directory which, by default, is located at `~/.cache/pip`. +Saving this cache in GitHub's cache allows us to save time when installing those packages. As a matter of fact, before installing packages, pip's cache can be restored using [**restore_pip_cache**](../restore_pip_cache/README.md) action. + +The action is composed of three steps: + +1. **Generate random UUID** - This step computes a random UUID, using shell command `uuidgen`, which will be part of the cache key. The uniqueness of the UUID ensures that there will be no collisions between cache keys, which is crucial because **GitHub won't allow the creation of two caches with the same key** (cache update/overwrite **is not supported**). +2. **Get pip cache directory** - This step retrieves the path to the pip cache. If *custom_pip_cache_path* is not an empty string, it will be used as pip cache path. Otherwise, the pip cache will be computed using `pip cache dir`. +3. **Save pip cache** - This step performs the heavy lifting of the caching. Using GitHub's [**cache/save**](https://github.com/actions/cache/blob/main/save/README.md) action, the cache is saved with a key composed of: + 1. The git reference input, *git_reference* + 2. A static part, `pip-cache` + 3. The previously computed UUID + +## Documentation + +### Inputs + +* **custom_pip_cache** - Optional - Path to the pip cache. It can be used for setting a custom pip cache path. It defaults to an empty string. In this case, the pip cache path will be computed using `pip cache dir`. More information regarding the previous command is available [here](https://pip.pypa.io/en/stable/cli/pip_cache/#description) +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. diff --git a/actions/python_requirements/save_pip_cache/action.yml b/actions/python_requirements/save_pip_cache/action.yml index 165bcf4..d98e398 100644 --- a/actions/python_requirements/save_pip_cache/action.yml +++ b/actions/python_requirements/save_pip_cache/action.yml @@ -1,8 +1,8 @@ -name: Composite action save pip's cache -description: Composite action to save pip's cache +name: Composite action save pip cache +description: Composite action to save pip cache inputs: custom_pip_cache_path: - description: Path to pip cache. + description: Path to the pip cache. required: false git_reference: description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. @@ -27,6 +27,7 @@ runs: else echo "pip_cache_path=${{ inputs.custom_pip_cache_path }}" >> $GITHUB_OUTPUT fi + echo "::debug::The pip cache path is $pip_cache_path" shell: bash - name: Save pip cache uses: actions/cache/save@v4 diff --git a/actions/python_requirements/save_virtualenv/README.md b/actions/python_requirements/save_virtualenv/README.md new file mode 100644 index 0000000..19d9ab5 --- /dev/null +++ b/actions/python_requirements/save_virtualenv/README.md @@ -0,0 +1,23 @@ +# Composite action save Python virtual environment + +This action saves a Python virtual environment to GitHub's cache. + +Combined with [**restore_virtualenv**](../restore_virtualenv/README.md), **it helps save time by avoiding the installation of Python requirements**. + +The action is composed of two steps: + +1. **Compute requirements files SHA256 hash** - This step uses [**misc/compute_files_hash**](../../misc/compute_files_hash/README.md) to compute a single SHA256 hash of the files described by the *requirements_paths*. The computed SHA256 hash will be part of the cache key. +2. **Cache virtual environment** - This step does the heavy lifting of saving the virtual environment to GitHub's cache. It uses the GitHub's [**cache/save**](https://github.com/actions/cache/blob/main/save/README.md) action with the following parameters: + 1. **path** - A list of files, directories, or paths to cache - set to the virtual environment path input variable *virtual_environment_path*. + 2. **key** - An explicit key for a cache entry - set to the combination of three strings: + 1. *git_reference*, provided as an input to the action. + 2. A static part, `-venv-` + 3. The previously computed SHA256 hash of the requirements files. + +## Documentation + +### Inputs + +* **virtual_environment_path** - Optional - Path where the virtual environment is located. It may be used to provide a custom path for the virtual environment. It defaults to `.venv`. +* **requirements_paths** - Required - A space separated list of requirements file paths. They will be used to compute a SHA256 hash used in the cache key. +* **git_reference** - Optional - A git reference that will be used to build the cache key. It defaults to `github.ref_name` which is a context variable containing **the short ref name of the branch or tag that triggered the workflow run**. For example it may be `feature-branch-1` or, for pull requests, `/merge`. diff --git a/actions/python_requirements/save_virtualenv/action.yml b/actions/python_requirements/save_virtualenv/action.yml index b93d66c..6c6c66c 100644 --- a/actions/python_requirements/save_virtualenv/action.yml +++ b/actions/python_requirements/save_virtualenv/action.yml @@ -2,12 +2,12 @@ name: Composite action save Python virtual environment description: Composite action to save Python virtual environment inputs: virtual_environment_path: - description: Path to virtual environment. + description: Path to the virtual environment. required: false default: ".venv" requirements_paths: - description: Comma separeted list of requirements files. They will be used to compute the hash for the cache key. - required: false + description: Space separeted list of requirements files. They will be used to compute the hash for the cache key. + required: true git_reference: description: A git reference (name of the branch, reference to the PR) that will be used to build the cache key. required: false @@ -26,4 +26,4 @@ runs: uses: actions/cache/save@v4 with: path: ${{ inputs.virtual_environment_path }} - key: ${{ inputs.git_reference }}-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} \ No newline at end of file + key: ${{ inputs.git_reference }}-venv-${{ steps.compute_requirements_files_sha256_hash.outputs.computed_hash }} \ No newline at end of file diff --git a/configurations/python_linters/requirements-linters.txt b/configurations/python_linters/requirements-linters.txt index 1f6b203..d8e8a4c 100644 --- a/configurations/python_linters/requirements-linters.txt +++ b/configurations/python_linters/requirements-linters.txt @@ -1,6 +1,9 @@ autoflake~=2.3.1 bandit~=1.8.3 black~=25.1.0 +# use fork since main repo is not updated +# see https://github.com/rocioar/flake8-django/pull/134 +# Note: python 3.12 is not supported flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89d275dfd5514f2aa9d091aa36c5ff84b flake8~=7.1.2 isort~=6.0.1 diff --git a/workflows/README.md b/workflows/README.md new file mode 100644 index 0000000..5bbea49 --- /dev/null +++ b/workflows/README.md @@ -0,0 +1,214 @@ +# Worflows + +## [Reusable detect changes workflow](_detect_changes.yml) + +This sub workflow detects and enumerates the changes between two branches. + +It is composed of five steps: + +1. **Check out PR target branch** - This step checks out the latest commit of the PR target branch for the current repository. This workflow was designed to detect changes when a PR to a target branch was created. Therefore, the latest commit of the target branch must be checked out as the first step. To achieve this, GitHub's [**checkout**](https://github.com/actions/checkout) action is used with the following parameters: + 1. **ref** - The branch, tag or SHA to checkout - It is set to `github.base_ref`, which corresponds to the **PR target branch**. +2. **Check out source branch latest commit** - This step checks out the latest commit of the source branch on top of the previous one. To do so, GitHub's [**checkout**](https://github.com/actions/checkout) action is used with the following parameters: + 1. **clean** - Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching - It is set to false, which means **do not delete untracked files**. +3. **Generate summary** - This step creates the title for the action summary. As a matter of fact, the detected changes will be reported below the title in the summary section. The step is performed only if one or both *backend_directories* and *frontend_directories* inputs are not empty. +4. **Generate diffs for backend** - This step detects and enumerates the files that changed between the two branches. This is performed using [`git diff`](https://git-scm.com/docs/git-diff) command. Specifically, the code instructs git to show the changes in the *backend_directories* relative to `origin/` (the target branch). During this process, the [**pathspec**](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec) is used to exclude files or directories specified in the *backend_exclusions* input. The changes are then enumerated and output through the *backend* variable. +5. **Generate diffs for frontend** - This step follow the same pattern as the **Generate diffs for backend** step but for the frontend directories. + +### Documentation + +#### Inputs + +* **backend_directories** - Optional - Space separated list of backend directories to check for changes. By default, it is set to an empty string. +* **backend_exclusions** - Optional - Space separated list of backend files or directories to **exclude** when checking for changes. Globs are supported. By default, it is set to an empty string. +* **frontend_directories** - Optional - Space separated list of frontend directories to check for changes. By default, it is set to an empty string +* **frontend_exclusions** - Optional - Space separated list of frontend files or directories to **exclude** when checking for changes. Globs are supported. By default, it is set to an empty string. +* **ubuntu_version** - Optional - The Ubuntu version to run the workflow against. By default, it is set to `latest`. + +#### Outputs + +* **backend** - The number of backend files that have changed. +* **frontend** - The number of frontend files that have changed. + +## [Reusable node tests workflow](_node.yml) + +This sub workflow install node dependencies and run frontend linters and tests. + +It is composed of nine steps: + +1. **Check out latest commit for current branch** - This step checks out the latest commit for the current branch of the repository. To do so, it uses GitHub's [**checkout**](https://github.com/actions/checkout) action with no parameters. +2. **Set up Node.js** - This step sets Node.js up downloading binaries and project's dependencies. This is done using the GitHub's [**setup-node**](https://github.com/actions/setup-node) action which also allows to cache and restore the project dependencies. It's used with the following parameters: + 1. **node-version** - Node.js version to use - It is set according to *node_version* input variable. + 2. **cache** - Which package manager used to install and cache packages - It is set to `npm`. + 3. **cache-dependency-path** - Path to the dependency file: `package-lock.json`, `yarn.lock` etc. It is set to `/package-lock.json`, where *working_directory* is the input variable. +3. **Add dependencies** - This step adds additional dependencies to the `package-lock.json` file. Specifically, these packages are added to the **devDependencies** part of the aforementioned file. Which packages will be added is chosen accordingly to input variables: + 1. *use_jest* + 2. *use_react* + 3. *use_eslint* + 4. *use_prettier* + 5. *use_stylelint* +4. **Install packages** - This step install all missing packages from the dependency file in the directory specified by the *working_directory* input variable. +5. **Run linters** - This step uses [**node_linter**](../actions/node_linter/action.yml) action to run linters against the frontend source code. +6. **Check packages licenses** - This step uses [**pilosus/action-pip-license-checker**](https://github.com/pilosus/action-pip-license-checker) to check the licenses used by the project requirements. +7. **Run CodeQL** - This step uses [**codeql**](../actions/codeql/action.yml) action to run CodeQL to discover vulnerabilities across the codebase. +8. **Run custom command** - This step is performed only if the input variable *custom_command* is not empty. The step simply run the bash command described in the previously mentioned input variable in the working directory specified by the *working_directory* input variable. +9. **Run jest tests** - This step runs Jest tests if the input variable *use_jest* is set to true. Finally, if *use_coverage* and *upload_coverage* are set to true, a coverage report is generated and uploaded. + +### Documentation + +#### Inputs + +* **node_versions** - Required - An array of Node.js versions to use. +* **working_directory** - Required - Path to the `package.json` file +* **check_packages_licenses** - Optional - Whether to check npm packages licenses or not. By default it is set to true. +* **use_jest** - Optional - Whether to use Jest test suite or not. By default it is set to false. +* **use_react** - Optional - Whether react is used by the project or not. By default it is set to false. +* **use_eslint** - Optional - Whether to use ESlint linter or not. By default it is set to true +* **use_prettier** - Optional - Whether to use Prettier formatter or not. By default it is set to true. +* **use_stylelint** - Optional - Whether to use Stylelint linter or not. By default it is set to true. +* **use_coverage** - Optional - Whether to use Coverage or not. To work, it also require *use_jest* to be true. By default it is set to false. +* **upload_coverage** - Optional - Whether to upload coverage report to GitHub. By default it is set to false +* **run_codeql** - Optional - Whether to run CodeQL against the codebase. By default it is set to false. +* **custom_command** - Optional - A custom bash command to be run by the workflow. By default it is set to an empty string. +* **max_timeout** - Optional - A maximum amount of minutes allowed for the workflow to run. By default it is set to 30. +* **ubuntu_version** - Optional - The Ubuntu version to run the workflow against. By default it is set to `latest`. + +## [Reusable python linter workflow](_python.yml) + +This sub workflow runs Python linters and tests against the codebase. + +It is composed of one job: + +1. **python** - This job is composed of thirty-one steps: + 1. **Check out latest commit** - Checks out the latest commit on the current branch of the repository using the GitHub's [**checkout**](https://github.com/actions/checkout) action. + 2. **Set up Python** - Sets up Python on the runner machine using GitHub's [**setup-python**](https://github.com/actions/setup-python) action with the following parameter: + 1. **python-version** - Which Python version to use - It is set according to the *python_versions* input variable. + 3. **Inject stuff to environment** - This step adds a few environment variables to the system's environment. Specifically: + 1. If *django_settings_module* is set, **PYTHONPATH** and **DJANGO_SETTINGS_MODULE** will be added to the runner's environment. + 2. If *run_codeql* is true, **CODEQL_PYTHON** will be added to the runner's environment. + 4. **Restore APT cache related to PR event** - This step will try to restore the APT cache related to the PR event using [**restore_apt_cache**](../actions/apt_requirements/restore_apt_cache/README.md) with the following parameter: + 1. **apt_requirements_file_path** - Path to the APT requirements file - It is set to the *packages_path* input variable. + 5. **Restore APT cache related to target branch** - This step will try to restore the APT cache related related to the target branch (of the PR) using [**restore_apt_cache**](../actions/apt_requirements/restore_apt_cache/README.md) only if **Restore APT cache related to PR event** produces a cache miss. It is run with the following parameter: + 1. **apt_requirements_file_path** - Path to the APT requirements file - It is set to the *packages_path* input variable. + 2. **git_reference** - A git reference (name of the branch, reference to the PR) that will be used to build the cache key - It is set to the target branch. + 6. **Restore APT repositories** - If both PR event and target branch APT cache restore attempt resulted in a cache miss, the APT repositories list is refreshed using `sudo apt-get update`. + 7. **Install APT requirements** - This step installs APT requirements listed in the *packages_path* requirements file. **Since they are not required, recommended packages are not downloaded**. + 8. **Save APT cache related to PR event** - When the attempt to restore the APT cache related to the PR event results in a cache miss, the newly populated APT cache is saved to GitHub. This is performed using [**save_apt_cache**](../actions/apt_requirements/save_apt_cache/README.md) action with the following parameter: + 1. **apt_requirements_file_path** - Path to the APT requirements file - It is se to the *packages_path* input variable. + 9. **Create linter requirements file** - This step creates the linter requirements file using the [**create_linter_requirements_file**](../actions/python_requirements/create_linter_requirements_file/README.md) action. + 10. **Create dev requirements file** - This step creates the development requirements file using the [**create_dev_requirements_file**](../actions/python_requirements/create_dev_requirements_file/README.md) action. + 11. **Create docs requirement file** - This step creates the documentation requirements file using the [**create_docs_requirements_file**](../actions/python_requirements/create_docs_requirements_file/README.md) action. + 12. **Restore Python virtual environment related to PR event** - This step attempts to restore the Python virtual environment for the PR using the [**restore_python_virtualenv**](../actions/python_requirements/restore_virtualenv/README.md) action. + 13. **Restore Python virtual environment related to target branch** - If the attempt to restore the Python virtual environment for the PR, result in a cache miss, an attempt to restore the Python virtual environment for the target branch is made using the [**restore_python_virtualenv**](../actions/python_requirements/restore_virtualenv/README.md) action. + 14. **Create Python virtual environment** - If both attempts to restore the Python virtual environment for the PR, for the target branch, result in a cache miss, a Python virtual environment is created using the [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action. + 15. **Restore pip cache related to PR event** - If both attempts to restore the Python virtual environment for the PR, for the target branch, result in a cache miss, an attempt to restore the pip cache for the PR event is made using the [**restore_pip_cache**](../actions/python_requirements/restore_pip_cache/README.md) action. + 16. **Restore pip cache related to target branch** - If both attempts to restore the Python virtual environment for the PR, for the target branch, as well as the pip cache for the PR, result in a cache miss, an attempt to restore the pip cache for the target branch is made using the [**restore_pip_cache**](../actions/python_requirements/restore_pip_cache/README.md) action. + 17. **Install project requirements** - If both attempts to restore the Python virtual environment for the PR event, and the target branch result in a cache miss, project requirements are installed from the working directory specified by the *install_from* input variable. + 18. **Install other requirements** - If the attempt to restore the Python virtual environment for the PR event result in a cache miss, developer, linters and documentation requirements are installed from the working directory specified by *working_directory* input variable. + 19. **Check requirements licenses** - If the input variable *check_requirements_licenses* is set to true and the attempt to restore the Python virtual environment related to the PR event result in a cache miss, this step performs the requirements licenses check using [**pilosus/action-pip-license-checker**](https://github.com/pilosus/action-pip-license-checker). + 20. **Print wrong licenses** - If the output of **Check requirements licenses** is `failure`, the list of licenses for which the check failed will be returned. + 21. **Save Python virtual environment related to PR event** - If the attempt to restore the Python virtual environment resulted in a cache miss, the Python virtual environment is saved for the PR event using the [*save_virtualenv*](../actions/python_requirements/save_virtualenv/README.md) action with the following parameter: + 1. **requirements_paths** - A space separated list of requirements file paths - It is set to the combination of *requirements_path*, `requirements-linters.txt`, `requirements-dev.txt` and `requirements-docs.txt` joined by spaces. + 22. **Save pip cache related to PR event** - If both attempts to restore the Python virtual environment and the pip cache related to the PR resulted in a cache miss, the pip cache is saved for the PR event using the [*save_pip_cache*](../actions/python_requirements/save_pip_cache/README.md) action. + 23. **Run linters** - If one of the following input variables: *use_black*, *use_isort*, *use_flake8*, *use_pylint*, *use_bandit* and *use_autoflake* is true, this step executes the linters against the codebase in the working directory specified by the *working_directory* variable. + 24. **Run CodeQL** - If the *run_codeql* input variable is true, this step runs CodeQL against the codebase using the [**codeql**](../actions/codeql/action.yml) action in the working directory specified by the *working_directory* variable. + 25. **Build Docs** - If the *check_docs_directory* input variable is set, this step executes `rstcheck` to ensure that the documentation in *check_docs_directory* is valid. Finally, the documentation is built using `sphinx`. + 26. **Start services** - If one or more of the following input variables: *use_postgres*, *use_elastic_search*, *use_memcached*, *use_redis*, *use_rabbitmq* and *use_mongo* are true, this step creates the Docker container for the service using the [**services**](../actions/services/action.yml) action. Additional parameters, such as *postgres_db* or *elasticsearch_version* can also be provided to the aforementioned action. + 27. **Start celery worker** - If the *use_celery* input variable is true, a Celery worker is created for the *celery_app* application. The `celery` command is executed in the working directory specified by the *working_directory* input variable. + 28. **Run custom command** - If the *custom_command* input variable is not empty, the command defined by the variable is executed in the working directory specified by the *working_directory* input variable. + 29. **Check migrations** - If *check_migrations* is true and *django_settings_module* is not empty, this step will perform a dry run of `django-admin makemigrations` to ensure that the migrations are valid. + 30. **Run unittest** - This step runs Python tests against the codebase in the directory described by the *working_directory* input variable. Additionally, according to *tags_for_manual_tests* and *tags_for_slow_tests* variables, some tests will be excluded from the run. + 31. **Create coverage output** - If *use_coverage* and *upload_coverage* are set to true, this step produces a coverage report of the codebase and uploads it to GitHub. The *working_directory* input variable is used to determines the directory in which coverage should be run. + +### Documentation + +#### Inputs + +* **python_versions** - Required - Python versions used by this workflow in the form of a JSON array. +* **ubuntu_version** - Optional - Ubuntu version to run workflow against. By default, it is set to `latest`. +* **working_directory** - Required - Directory in which to run linters. +* **requirements_path** - Required - Path to the requirements file of the Python project. +* **install_from** - Optional - Directory where all installation commands will be run. By default, it is set to `.`. +* **packages_path** - Optional - Path to the APT requirements file of the Python project. By default, it is set to an empty string. +* **env** - Optional - A JSON object containing a set of environment variables to be added to the system's environment. By default, it is set to an empty JSON object `{}`. +* **max_timeout** - Optional - Maximum amount of time (in minutes) the workflow is allowed to run. By default, it is set to `30`. +* **use_black** - Optional - Whether to use black formatter. By default, it is set to `false`. +* **use_isort** - Optional - Whether to use isort formatter. By default, it is set to `false`. +* **use_autoflake** - Optional - Whether to use autoflake linter. By default, it is set to `false`. +* **use_bandit** - Optional - Whether to use bandit linter. By default, it is set to `false`. +* **use_flake8** - Optional - Whether to use flake8 linter. By default, it is set to `false`. +* **use_pylint** - Optional - Whether to use pylint linter. By default, it is set to `false`. +* **use_coverage** - Optional - Whether to use coverage. By default, it is set to `false`. +* **coverage_config_path** - Optional - Path to the coverage configuration file. By default, it is set to `.coveragerc`. +* **upload_coverage** - Optional - Whether to upload coverage report to GitHub. To work, it needs *use_coverage* to be true. By default, it is set to `false`. +* **run_codeql** - Optional - Whether to run CodeQL against codebase. By default, it is set to `false`. +* **use_celery** - Optional - Whether to create a Celery container. By default, it is set to `false`. +* **use_elastic_search** - Optional - Whether to create an Elasticsearch container. By default, it is set to `false`. +* **use_memcached** - Optional - Whether to create a Memcached container. By default, it is set to `false`. +* **use_mongo** - Optional - Whether to create a MongoDB container. By default, it is set to `false`. +* **use_postgres** - Optional - Whether to create a PostgresDB container. By default, it is set to `false`. +* **use_rabbitmq** - Optional - Whether to create a RabbitMQ container. By default, it is set to `false`. +* **use_redis** - Optional - Whether to create a Redis container. By default, it is set to `false`. +* **celery_app** - Optional - A Celery application name. Requires *use_celery* to be true. By default, it is set to an empty string. +* **celery_queues** - Optional - A comma separated list of Celery queues. Requires *use_celery* to be true. By default, it is set to `default`. +* **elasticsearch_version** - Optional - Elasticsearch's container version. By default, it is set to `latest`. +* **elasticsearch_port** - Optional - Elasticsearch's container exposed port. By default, it is set to `9200`. +* **memcached_version** - Optional - Mecached's container version. By default, it is set to `latest`. +* **mongo_version** - Optional - MongoDB's container version. By default, it is set to `latest`. +* **postgres_db** - Optional - PostgresDB database name. Requires *use_postgres* to be true. By default, it is set to `db`. +* **postgres_user** - Optional - PostgresDB user name. Requires *use_postgres* to be true. By default, it is set to `user`. +* **postgres_password** - Optional - PostgresDB password. Requires *use_postgres* to be true. By default, it is set to `password`. +* **postgres_version** - Optional - PostgresDB's container version. Requires *use_postgres* to be true. By default, it is set to `latest`. +* **rabbitmq_version** - Optional - RabbitMQ's container version. Requires *use_rabbitmq* to be true. By default, it is set to `latest`. +* **redis_version** - Optional - Redis' container version. Requires *use_redis* to be true. By default, it is set to `latest`. +* **django_settings_module** - Optional - Path to the Django settings file. By default, it is set to an empty string. +* **check_migrations** - Optional - Whether to check that the project's migrations are valid. Requires *django_settings_module* to be set. By default, it is set to `false`. +* **check_requirements_licenses** - Optional - Whether to check that the requirements license is valid. Requires *django_settings_module* to be set. By default, it is set to `true`. +* **ignore_requirements_licenses_regex** - Optional - A regex that describes which directories should be ignored when checking the validity of requirements licenses. By default, it is set to `uWSGI.*|lunardate.*|.*QuokkaClient.*|pyquokka.*`. +* **tags_for_slow_tests** - Optional - A space separated list of tags for tests that will only be run on the master/main branch. **Works only for Django projects**. By default, it is set to an `slow`. +* **tags_for_manual_tests** - Optional - A space separated list of tags for tests that will only be run **manually** (CI will ignore them). **Works only for Django projects**. By default, it is set to `manual`. +* **custom_command** - Optional - A custom bash command to run. By default, it is set to an empty string. +* **check_docs_directory** - Optional - Path to the documentation directory in which `rstcheck` will be run to check documentation files. By default, it is set to an empty string. +* **check_dockerfile** - Optional - Path to a Dockerfile to be checked. **Warning: if set it may significantly increase the action time**. By default, it is set to an empty string. + +## [Create APT cache](create_apt_cache.yaml) + +This workflow is run in the event of **a push on branches *main*, *master*, *develop*, *dev***. Specifically, it is triggered only when the APT requirements file is updated. + +The workflow is composed of a single job: + +1. **Create cache for APT dependencies** - This job, as described by its name, creates a cache for APT dependencies and stores it on GitHub. It is composed of four steps: + 1. **Check out latest commit on current branch** - This step checks out the latest commit on the current branch of the repository. + 2. **Install APT dependencies** - This step refreshes APT repositories and then install the project dependecies. This action is required to produce the APT cache that will be saved later. + 3. **Save APT cache** - This step saves APT cache on GitHub. The GitHub's [**save_apt_cache**](../actions/apt_requirements/save_apt_cache/README.md) action is used. + +## [Create Python cache](create_python_cache.yaml) + +This workflow is run in the event of **a push on branches *main*, *master*, *develop*, *dev***. Specifically, it is triggered only when the Python requirements file is updated. + +The workflow is composed of a single job: + +1. **Create cache for Python dependencies** - This job, as described by its name, creates a cache for Python dependencies and stores it on GitHub. It is composed of four steps: + 1. **Check out latest commit** - This step checks out the latest commit on the current branch for the repository. + 2. **Set up Python** - This step install Python on the runner. + 3. **Set up Python virtual environment** - This step uses [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action to create a Python virtual environment. + 4. **Install Python dependencies** - This step install Python requirements to produce the final virtual environment that will be cached. Also, installing the Python dependencies, creates the pip cache. + 5. **Save pip cache** - This step uses [**save_pip_cache**](../actions/python_requirements/save_pip_cache/README.md) action to save pip's download cache on GitHub. + 6. **Create virtual environment cache** - This step uses [**save_virtualenv**](../actions/python_requirements/save_virtualenv/README.md) action to save virtual environment on GitHub's cache. + +## [CI](pull_request_automation.yml) + +This workflow runs in the case of a **pull request on branches *master*, *main*, *develop*, *dev*** and it's the core CI workflow. + +It is composed of three jobs: + +1. **detect-changes** - This job detects and enumerates changes to backend and/or frontend files. To do so, it uses the [**_detect_changes**](_detect_changes.yml) workflow. +2. **node** - If any changes to the frontend files are found, [**_node**](_node.yml) workflow is run. +3. **python** - If any changes to the backend files are found, [**_python**](_python.yml) workflow is run. + +## [Release and publish](release.yml) + +TODO + +## [Reusable release and tag workflow](_release_and_tag.yml) + +TODO diff --git a/workflows/_detect_changes.yml b/workflows/_detect_changes.yml index eb68be3..9e9b8a6 100644 --- a/workflows/_detect_changes.yml +++ b/workflows/_detect_changes.yml @@ -3,22 +3,22 @@ on: workflow_call: inputs: backend_directories: - description: Backend directories separated by spaces + description: Space separated list of backend directories required: false type: string backend_exclusions: - description: Backend directories or files to be excluded separated by spaces + description: Space separated list of Backend directories or files to be excluded required: false type: string frontend_directories: - description: Frontend directories separated by spaces + description: Space separated list of frontend directories required: false type: string frontend_exclusions: - description: Frontend directories or files to be excluded separated by spaces + description: Space separated list of frontend directories or files to be excluded required: false type: string @@ -45,13 +45,16 @@ jobs: backend: ${{steps.diff_check_backend.outputs.backend}} frontend: ${{steps.diff_check_frontend.outputs.frontend}} steps: - - uses: actions/checkout@v4 + - name: Check out PR target branch + uses: actions/checkout@v4 with: ref: ${{ github.base_ref }} - - uses: actions/checkout@v4 + - name: Check out source branch latest commit + uses: actions/checkout@v4 with: clean: false + - name: Generate summary if: ${{inputs.backend_directories != ''}} | ${{inputs.frontend_directories != ''}} run: | @@ -76,7 +79,6 @@ jobs: echo "::debug::diff command results: $(git diff --compact-summary origin/${{ github.base_ref }} -- ${{ inputs.backend_directories }} $BACKEND_EXCLUSIONS | head -n -1 )" echo "backend $BACKEND_CHANGES" - - name: Generate diffs for frontend if: ${{inputs.frontend_directories != ''}} id: diff_check_frontend diff --git a/workflows/_node.yml b/workflows/_node.yml index 1a850b0..074bbe1 100644 --- a/workflows/_node.yml +++ b/workflows/_node.yml @@ -88,7 +88,8 @@ jobs: node_version: ${{ fromJson(inputs.node_versions) }} language: ['javascript'] steps: - - uses: actions/checkout@v4 + - name: Check out latest commit for current branch + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 diff --git a/workflows/_python.yml b/workflows/_python.yml index 1f6624f..e2142b1 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -245,7 +245,8 @@ jobs: language: ['python'] env: ${{ fromJson(inputs.env) }} steps: - - uses: actions/checkout@v4 + - name: Check out latest commit + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 @@ -264,33 +265,39 @@ jobs: shell: bash - - name: Install apt requirements - if: inputs.packages_path - uses: ./.github/actions/apt_requirements + - name: Restore APT cache related to PR event + id: restore_apt_cache_pr + uses: ./.github/actions/apt_requirements/restore_apt_cache with: - requirements_file: ${{ inputs.packages_path }} - - - name: Check requirements licenses - if: inputs.check_requirements_licenses && steps.cache-virtualenv.outputs.cache-hit != 'true' - id: license_check_report - continue-on-error: true - uses: pilosus/action-pip-license-checker@v2 + apt_requirements_file_path: ${{ inputs.packages_path }} + + - name: Restore APT cache related to target branch + id: restore_apt_cache_target_branch + if: steps.restore_apt_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/apt_requirements/restore_apt_cache with: - requirements: ${{ inputs.install_from }}/${{ inputs.requirements_path }} - exclude: ${{ inputs.ignore_requirements_licenses_regex }} - headers: true - fail: 'StrongCopyleft,NetworkCopyleft,Error' - fails-only: true + apt_requirements_file_path: ${{ inputs.packages_path }} + git_reference: ${{ github.base_ref }} + + - name: Refresh APT repositories + if: > + steps.restore_apt_cache_pr.outputs.cache-hit != 'true' && + steps.restore_apt_cache_target_branch.outputs.cache-hit != 'true' + run: | + sudo apt-get update + shell: bash - - name: Print wrong licenses - if: steps.license_check_report.outcome == 'failure' + - name: Install APT requirements run: | - echo "License check failed" - echo "====================" - echo "${{ steps.license_check_report.outputs.report }}" - echo "====================" - exit 1 + sudo apt-get install -y --no-install-recommends $(tr '\n' ' ' < ${{ inputs.packages_path }}) shell: bash + + - name: Save APT cache related to PR event + if: > + steps.restore_apt_cache_pr.outputs.cache-hit != 'true' + uses: ./.github/actions/apt_requirements/save_apt_cache + with: + apt_requirements_file_path: ${{ inputs.packages_path }} - name: Create linter requirements file uses: ./.github/actions/python_requirements/create_linter_requirements_file @@ -319,7 +326,7 @@ jobs: id: restore_python_virtual_environment_pr uses: ./.github/actions/python_requirements/restore_virtualenv/ with: - requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" + requirements_paths: "${{ inputs.requirements_path }} requirements-linters.txt requirements-dev.txt requirements-docs.txt" - name: Restore Python virtual environment related to target branch id: restore_python_virtual_environment_target_branch @@ -370,14 +377,38 @@ jobs: shell: bash working-directory: ${{ inputs.install_from }} - - name: Save Python virtual environment related to the PR event + - name: Check requirements licenses + if: > + inputs.check_requirements_licenses && + steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' + id: license_check_report + continue-on-error: true + uses: pilosus/action-pip-license-checker@v2 + with: + requirements: ${{ inputs.install_from }}/${{ inputs.requirements_path }} + exclude: ${{ inputs.ignore_requirements_licenses_regex }} + headers: true + fail: 'StrongCopyleft,NetworkCopyleft,Error' + fails-only: true + + - name: Print wrong licenses + if: steps.license_check_report.outcome == 'failure' + run: | + echo "License check failed" + echo "====================" + echo "${{ steps.license_check_report.outputs.report }}" + echo "====================" + exit 1 + shell: bash + + - name: Save Python virtual environment related to PR event if: > steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' uses: ./.github/actions/python_requirements/save_virtualenv with: - requirements_paths: "${{ inputs.requirements_path }},requirements-linters.txt,requirements-dev.txt,requirements-docs.txt" + requirements_paths: "${{ inputs.requirements_path }} requirements-linters.txt requirements-dev.txt requirements-docs.txt" - - name: Save pip cache related to the PR event + - name: Save pip cache related to PR event if: > steps.restore_python_virtual_environment_pr.outputs.cache-hit != 'true' && steps.restore_pip_cache_pr.outputs.cache-hit != 'true' diff --git a/workflows/create_apt_cache.yaml b/workflows/create_apt_cache.yaml index 06f26cc..9bd5fd7 100644 --- a/workflows/create_apt_cache.yaml +++ b/workflows/create_apt_cache.yaml @@ -23,7 +23,8 @@ jobs: name: Create cache for APT dependencies runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Check out latest commit on current branch + uses: actions/checkout@v4 # Remember to set the same APT requirements file path set before! - name: Install APT dependencies @@ -31,13 +32,7 @@ jobs: sudo apt-get update sudo apt-get -y install --no-install-recommends $(tr '\n' ' ' < .github/test/python_test/packages.txt) - - name: Compute apt_packages.txt SHA256 hash - id: compute_apt_packages_sha256_hash - uses: ./.github/actions/misc/compute_files_hash + - name: Save APT cache + uses: ./.github/actions/apt_requirements/save_apt_cache with: - file_paths: .github/test/python_test/packages.txt - - - uses: actions/cache/save@v4 - with: - path: /var/cache/apt/archives/*.deb - key: ${{ github.ref_name }}-${{ steps.compute_apt_packages_sha256_hash.outputs.computed_hash }} + apt_requirements_file_path: .github/test/python_test/packages.txt diff --git a/workflows/create_python_cache.yaml b/workflows/create_python_cache.yaml index a6b65b5..cac8510 100644 --- a/workflows/create_python_cache.yaml +++ b/workflows/create_python_cache.yaml @@ -32,7 +32,7 @@ jobs: with: python-version: "3.12" - - name: Set up Python's virtual environment + - name: Set up Python virtual environment uses: ./.github/actions/python_requirements/create_virtualenv - name: Install Python dependencies From 0599640d6d484631504aedbc57961591e4433985 Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Tue, 22 Apr 2025 10:55:45 +0200 Subject: [PATCH 12/15] Fixed create_python_cache workflow (#222) * Fixed create_python_cache workflow * Added documentation for intermediate APT install step in Create Python Cache workflow --- .github/workflows/create_python_cache.yaml | 5 +++++ workflows/README.md | 11 ++++++----- workflows/create_python_cache.yaml | 5 +++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/create_python_cache.yaml b/.github/workflows/create_python_cache.yaml index cac8510..8db85f4 100644 --- a/.github/workflows/create_python_cache.yaml +++ b/.github/workflows/create_python_cache.yaml @@ -27,6 +27,11 @@ jobs: - name: Check out latest commit uses: actions/checkout@v4 + # Uncomment only if necessary + #- name: Install system dependencies required by Python packages + # run: | + # sudo apt-get update && sudo apt install ... + - name: Set up Python uses: actions/setup-python@v5 with: diff --git a/workflows/README.md b/workflows/README.md index 5bbea49..63ae6b8 100644 --- a/workflows/README.md +++ b/workflows/README.md @@ -189,11 +189,12 @@ The workflow is composed of a single job: 1. **Create cache for Python dependencies** - This job, as described by its name, creates a cache for Python dependencies and stores it on GitHub. It is composed of four steps: 1. **Check out latest commit** - This step checks out the latest commit on the current branch for the repository. - 2. **Set up Python** - This step install Python on the runner. - 3. **Set up Python virtual environment** - This step uses [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action to create a Python virtual environment. - 4. **Install Python dependencies** - This step install Python requirements to produce the final virtual environment that will be cached. Also, installing the Python dependencies, creates the pip cache. - 5. **Save pip cache** - This step uses [**save_pip_cache**](../actions/python_requirements/save_pip_cache/README.md) action to save pip's download cache on GitHub. - 6. **Create virtual environment cache** - This step uses [**save_virtualenv**](../actions/python_requirements/save_virtualenv/README.md) action to save virtual environment on GitHub's cache. + 2. **Install system dependencies required by Python Packages** - **OPTIONAL** - Sometimes, Python packages require one or more system dependencies. For instance, `python-ldap` Python package requires `libldap2-dev` and `libsasl2-dev`, System dependencies, for a successful installation. This step allows user to install system dependencies required by Python packages. + 3. **Set up Python** - This step install Python on the runner. + 4. **Set up Python virtual environment** - This step uses [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action to create a Python virtual environment. + 5. **Install Python dependencies** - This step install Python requirements to produce the final virtual environment that will be cached. Also, installing the Python dependencies, creates the pip cache. + 6. **Save pip cache** - This step uses [**save_pip_cache**](../actions/python_requirements/save_pip_cache/README.md) action to save pip's download cache on GitHub. + 7. **Create virtual environment cache** - This step uses [**save_virtualenv**](../actions/python_requirements/save_virtualenv/README.md) action to save virtual environment on GitHub's cache. ## [CI](pull_request_automation.yml) diff --git a/workflows/create_python_cache.yaml b/workflows/create_python_cache.yaml index cac8510..8db85f4 100644 --- a/workflows/create_python_cache.yaml +++ b/workflows/create_python_cache.yaml @@ -27,6 +27,11 @@ jobs: - name: Check out latest commit uses: actions/checkout@v4 + # Uncomment only if necessary + #- name: Install system dependencies required by Python packages + # run: | + # sudo apt-get update && sudo apt install ... + - name: Set up Python uses: actions/setup-python@v5 with: From 0c262e273f2d1bc6835eba6c0a4a82e762cf4a72 Mon Sep 17 00:00:00 2001 From: Luca Cigarini Date: Tue, 22 Apr 2025 11:05:02 +0200 Subject: [PATCH 13/15] Updated CHANGELOG --- .github/workflows/README.md | 11 ++++++----- CHANGELOG.md | 8 ++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 5bbea49..63ae6b8 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -189,11 +189,12 @@ The workflow is composed of a single job: 1. **Create cache for Python dependencies** - This job, as described by its name, creates a cache for Python dependencies and stores it on GitHub. It is composed of four steps: 1. **Check out latest commit** - This step checks out the latest commit on the current branch for the repository. - 2. **Set up Python** - This step install Python on the runner. - 3. **Set up Python virtual environment** - This step uses [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action to create a Python virtual environment. - 4. **Install Python dependencies** - This step install Python requirements to produce the final virtual environment that will be cached. Also, installing the Python dependencies, creates the pip cache. - 5. **Save pip cache** - This step uses [**save_pip_cache**](../actions/python_requirements/save_pip_cache/README.md) action to save pip's download cache on GitHub. - 6. **Create virtual environment cache** - This step uses [**save_virtualenv**](../actions/python_requirements/save_virtualenv/README.md) action to save virtual environment on GitHub's cache. + 2. **Install system dependencies required by Python Packages** - **OPTIONAL** - Sometimes, Python packages require one or more system dependencies. For instance, `python-ldap` Python package requires `libldap2-dev` and `libsasl2-dev`, System dependencies, for a successful installation. This step allows user to install system dependencies required by Python packages. + 3. **Set up Python** - This step install Python on the runner. + 4. **Set up Python virtual environment** - This step uses [**create_virtualenv**](../actions/python_requirements/create_virtualenv/README.md) action to create a Python virtual environment. + 5. **Install Python dependencies** - This step install Python requirements to produce the final virtual environment that will be cached. Also, installing the Python dependencies, creates the pip cache. + 6. **Save pip cache** - This step uses [**save_pip_cache**](../actions/python_requirements/save_pip_cache/README.md) action to save pip's download cache on GitHub. + 7. **Create virtual environment cache** - This step uses [**save_virtualenv**](../actions/python_requirements/save_virtualenv/README.md) action to save virtual environment on GitHub's cache. ## [CI](pull_request_automation.yml) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8363d9..2d35238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 2.1.x + +## 2.1.0 + +### Changes + +* Added "Install system dependencies required by Python packages" step to "Create Python cache" workflow. + # 2.0.x ## 2.0.0 From 59bfe83eb47379fb0fe6a14b0712b314274b44f6 Mon Sep 17 00:00:00 2001 From: eugenioseveri Date: Mon, 21 Jul 2025 10:08:29 +0200 Subject: [PATCH 14/15] Explicitly disabled "xpack.security" in Elasticsearch container Also fixed changelog --- .github/actions/services/action.yml | 1 + .github/workflows/pull_request_automation.yml | 2 +- CHANGELOG.md | 27 +++++-------------- actions/services/action.yml | 1 + workflows/pull_request_automation.yml | 2 +- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/.github/actions/services/action.yml b/.github/actions/services/action.yml index b814a03..95cf213 100644 --- a/.github/actions/services/action.yml +++ b/.github/actions/services/action.yml @@ -104,6 +104,7 @@ runs: echo " environment:" >> elastic_search.yml echo " ES_JAVA_OPTS: -Xms1g -Xmx1g" >> elastic_search.yml echo " discovery.type: single-node" >> elastic_search.yml + echo " xpack.security.enabled: 'false'" >> elastic_search.yml echo " ports:" >> elastic_search.yml echo " - ${{ inputs.elasticsearch_port }}:9200" >> elastic_search.yml echo " healthcheck:" >> elastic_search.yml diff --git a/.github/workflows/pull_request_automation.yml b/.github/workflows/pull_request_automation.yml index 71deca6..7433a96 100644 --- a/.github/workflows/pull_request_automation.yml +++ b/.github/workflows/pull_request_automation.yml @@ -81,7 +81,7 @@ jobs: use_memcached: false memcached_version: latest use_elastic_search: false - elasticsearch_version: 8.11.1 + elasticsearch_version: 9.0.3 elasticsearch_port: 9200 use_rabbitmq: true rabbitmq_version: 3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d35238..c1fdbe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,13 @@ -# 2.1.x - -## 2.1.0 - -### Changes - -* Added "Install system dependencies required by Python packages" step to "Create Python cache" workflow. - -# 2.0.x - -## 2.0.0 - -### Features - +## 2.0.x +### 2.0.0 +#### Features * Added "release.yml" action to to push containers to AWS ECR * Added *create_apt_cache.yaml* workflow to cache APT requirements each time a commit is pushed on selected branch and **when the requirements file has changed**. * Added documentation. - -### Bugfix - +#### Bugfix * Updated python linters also in '_python.yml' workflow (missing from previous release) - -### Changes - +* Explicitly disabled `xpack.security` in Elasticsearch container, since it is enabled by default in newer versions of Elasticsearch +#### Changes * Deprecation of license check table-headers * Updated Python linters: * bandit 1.7.9 -> 1.8.3 @@ -39,3 +25,4 @@ * Updated some Github actions: * setup-python v4 -> v5 * action-gh-release v1 -> v2 +* Added "Install system dependencies required by Python packages" step to "Create Python cache" workflow. \ No newline at end of file diff --git a/actions/services/action.yml b/actions/services/action.yml index b814a03..95cf213 100644 --- a/actions/services/action.yml +++ b/actions/services/action.yml @@ -104,6 +104,7 @@ runs: echo " environment:" >> elastic_search.yml echo " ES_JAVA_OPTS: -Xms1g -Xmx1g" >> elastic_search.yml echo " discovery.type: single-node" >> elastic_search.yml + echo " xpack.security.enabled: 'false'" >> elastic_search.yml echo " ports:" >> elastic_search.yml echo " - ${{ inputs.elasticsearch_port }}:9200" >> elastic_search.yml echo " healthcheck:" >> elastic_search.yml diff --git a/workflows/pull_request_automation.yml b/workflows/pull_request_automation.yml index 71deca6..7433a96 100644 --- a/workflows/pull_request_automation.yml +++ b/workflows/pull_request_automation.yml @@ -81,7 +81,7 @@ jobs: use_memcached: false memcached_version: latest use_elastic_search: false - elasticsearch_version: 8.11.1 + elasticsearch_version: 9.0.3 elasticsearch_port: 9200 use_rabbitmq: true rabbitmq_version: 3 From 76df2c2232085911742abce6f7a838af84848311 Mon Sep 17 00:00:00 2001 From: Luca Cigarini <94375169+lucaCigarini@users.noreply.github.com> Date: Tue, 5 Aug 2025 16:45:30 +0200 Subject: [PATCH 15/15] added ruff and fixed a bug (#221) * added ruff and fixed a bug * fixed input * fixed stupid mistake * synced .github * disabled ruff formatter for this repo * ruff with defaults --- .github/actions/python_linter/action.yml | 37 +++++++++++--- .../create_linter_requirements_file/README.md | 5 ++ .../action.yml | 18 ++++++- .../configurations/python_linters/.ruff.toml | 51 +++++++++++++++++++ .../python_linters/requirements-linters.txt | 3 +- .github/workflows/README.md | 2 + .github/workflows/_python.yml | 24 ++++++++- .github/workflows/pull_request_automation.yml | 2 + .pre-commit-config.yaml | 9 ++++ CHANGELOG.md | 2 + actions/python_linter/action.yml | 37 +++++++++++--- .../create_linter_requirements_file/README.md | 5 ++ .../action.yml | 18 ++++++- configurations/python_linters/.ruff.toml | 51 +++++++++++++++++++ .../python_linters/requirements-linters.txt | 3 +- workflows/README.md | 2 + workflows/_python.yml | 24 ++++++++- workflows/pull_request_automation.yml | 2 + 18 files changed, 275 insertions(+), 20 deletions(-) create mode 100644 .github/configurations/python_linters/.ruff.toml create mode 100644 configurations/python_linters/.ruff.toml diff --git a/.github/actions/python_linter/action.yml b/.github/actions/python_linter/action.yml index 8c285e0..1bd4637 100644 --- a/.github/actions/python_linter/action.yml +++ b/.github/actions/python_linter/action.yml @@ -5,6 +5,12 @@ inputs: description: Directory that must be run against the linters required: true + use_autoflake: + description: Use autoflake + required: true + use_bandit: + description: Use bandit linter + required: true use_black: description: Use black formatter required: true @@ -17,11 +23,11 @@ inputs: use_pylint: description: Use pylint linter required: true - use_bandit: - description: Use bandit linter + use_ruff_formatter: + description: Use ruff formatter required: true - use_autoflake: - description: Use autoflake + use_ruff_linter: + description: Use ruff linter required: true runs: @@ -66,11 +72,9 @@ runs: else echo "Skipping isort linter" fi - working-directory: ${{ inputs.working_directory }} shell: bash - - name: bandit run: | if [[ ${{inputs.use_bandit }} != 'false' ]]; then @@ -78,7 +82,6 @@ runs: else echo "Skipping bandit linter" fi - working-directory: ${{ inputs.working_directory }} shell: bash @@ -90,4 +93,24 @@ runs: echo "Skipping autoflake" fi working-directory: ${{ inputs.working_directory }} + shell: bash + + - name: ruff formatter + run: | + if [[ ${{ inputs.use_ruff_formatter }} != 'false' ]]; then + ruff format --config ${GITHUB_WORKSPACE}/.github/configurations/python_linters/.ruff.toml --diff . + else + echo "Skipping ruff formatter" + fi + working-directory: ${{ inputs.working_directory }} + shell: bash + + - name: ruff linter + run: | + if [[ ${{ inputs.use_ruff_linter }} != 'false' ]]; then + ruff check --config ${GITHUB_WORKSPACE}/.github/configurations/python_linters/.ruff.toml . + else + echo "Skipping ruff linter" + fi + working-directory: ${{ inputs.working_directory }} shell: bash \ No newline at end of file diff --git a/.github/actions/python_requirements/create_linter_requirements_file/README.md b/.github/actions/python_requirements/create_linter_requirements_file/README.md index 9be5aa9..fafbb9b 100644 --- a/.github/actions/python_requirements/create_linter_requirements_file/README.md +++ b/.github/actions/python_requirements/create_linter_requirements_file/README.md @@ -13,6 +13,7 @@ As of today only the following linters are supported: * `isort` * `pylint` * `pylint-django` +* `ruff` ## Documentation @@ -23,5 +24,9 @@ As of today only the following linters are supported: * **django_settings_module** - Optional - Path to the Django settings file. It's used to make GitHub action aware of Django presence. In the case of a Django project, `flake8-django` and `pylint-django`, may be used and hence they will be added to the newly created requirements file. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no Django settings file**. * **use_autoflake** - Optional - Flag to state whether to use or not `autoflake` linter. It defaults to false. * **use_bandit** - Optional - Flag to state whether to use or not `bandit` linter. It defaults to false. +* **use_black** - Optional - Flag to state whether to use `black` formatter. It defaults to false. * **use_flake8** - Optional - Flag to state whether to use or not `flake8` linter. It defaults to false. +* **use_isort** - Optional - Flag to state whether to use or not `isort` formatter. It defaults to false. * **use_pylint** - Optional - Flag to state whether to use or not `pylint` linter. It defaults to false. +* **use_ruff_formatter** - Optional - Flag to state whether to use `ruff` **formatter** (so without the linting). It defaults to false. +* **use_ruff_linter** - Optional - Flag to state whether to use `ruff` **linter** (so without the formatting). It defaults to false. diff --git a/.github/actions/python_requirements/create_linter_requirements_file/action.yml b/.github/actions/python_requirements/create_linter_requirements_file/action.yml index 7edb47f..b7ac092 100644 --- a/.github/actions/python_requirements/create_linter_requirements_file/action.yml +++ b/.github/actions/python_requirements/create_linter_requirements_file/action.yml @@ -17,13 +17,24 @@ inputs: use_bandit: description: Use bandit linter required: false + use_black: + description: Use black formatter + required: false use_flake8: description: Use flake8 linter required: false + use_isort: + description: Use isort formatter + required: false use_pylint: description: Use pylint linter required: false - + use_ruff_formatter: + description: Use ruff formatter + required: false + use_ruff_linter: + description: Use ruff linter + required: false runs: @@ -76,10 +87,15 @@ runs: if [[ '${{ inputs.use_bandit }}' != 'false' ]]; then check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" fi + if [[ '${{ inputs.use_autoflake }}' != 'false' ]]; then check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" fi + if [[ '${{ inputs.use_ruff_formatter }}' != 'false' || '${{ inputs.use_ruff_linter }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "ruff" "$CI_REQUIREMENTS_LINTERS" + fi + if [[ -z '${{ inputs.project_linter_requirements_file }}' ]]; then cat $(echo ${{ inputs.project_linter_requirements_file }}) >> requirements-linters.txt fi diff --git a/.github/configurations/python_linters/.ruff.toml b/.github/configurations/python_linters/.ruff.toml new file mode 100644 index 0000000..601926e --- /dev/null +++ b/.github/configurations/python_linters/.ruff.toml @@ -0,0 +1,51 @@ +# Top level settings +## Reference: https://docs.astral.sh/ruff/settings/#top-level + +extend-exclude = [ + ".github", + ".idea", + ".vscode", + "**/migrations/*" +] + +include = ["*.py"] + +indent-width = 4 + +line-length = 160 + +output-format = "full" + +respect-gitignore = false + +show-fixes = true + +target-version = "py312" + +# Format settings level +## Reference: https://docs.astral.sh/ruff/settings/#format +[format] + +docstring-code-format = true + +indent-style = "space" + +line-ending = "native" + +quote-style = "double" + +skip-magic-trailing-comma = false + +[lint] + +# Default + Isort +select = [ + "E4", + "E7", + "E9", + "F", + # Isort - https://docs.astral.sh/ruff/rules/#isort-i + "I" +] + +ignore = [ ] diff --git a/.github/configurations/python_linters/requirements-linters.txt b/.github/configurations/python_linters/requirements-linters.txt index d8e8a4c..5f7cdde 100644 --- a/.github/configurations/python_linters/requirements-linters.txt +++ b/.github/configurations/python_linters/requirements-linters.txt @@ -8,4 +8,5 @@ flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89 flake8~=7.1.2 isort~=6.0.1 pylint-django~=2.6.1 -pylint~=3.3.5 \ No newline at end of file +pylint~=3.3.5 +ruff~=0.12.7 \ No newline at end of file diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 63ae6b8..258d5a1 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -133,10 +133,12 @@ It is composed of one job: * **max_timeout** - Optional - Maximum amount of time (in minutes) the workflow is allowed to run. By default, it is set to `30`. * **use_black** - Optional - Whether to use black formatter. By default, it is set to `false`. * **use_isort** - Optional - Whether to use isort formatter. By default, it is set to `false`. +* **use_ruff_formatter** - Optional - Whether to use ruff formatter. By default, it is set to `false`. * **use_autoflake** - Optional - Whether to use autoflake linter. By default, it is set to `false`. * **use_bandit** - Optional - Whether to use bandit linter. By default, it is set to `false`. * **use_flake8** - Optional - Whether to use flake8 linter. By default, it is set to `false`. * **use_pylint** - Optional - Whether to use pylint linter. By default, it is set to `false`. +* **use_ruff_linter** - Optional - Whether to use ruff linter. By default, it is set to `false`. * **use_coverage** - Optional - Whether to use coverage. By default, it is set to `false`. * **coverage_config_path** - Optional - Path to the coverage configuration file. By default, it is set to `.coveragerc`. * **upload_coverage** - Optional - Whether to upload coverage report to GitHub. To work, it needs *use_coverage* to be true. By default, it is set to `false`. diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index e2142b1..8c5c39f 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -50,6 +50,10 @@ on: description: Use isort formatter type: boolean required: false + use_ruff_formatter: + description: Use ruff formatter + type: boolean + required: false # Linters use_autoflake: @@ -68,6 +72,10 @@ on: description: Use pylint linter type: boolean required: false + use_ruff_linter: + description: Use ruff linter + type: boolean + required: false # Coverage configs use_coverage: @@ -306,8 +314,12 @@ jobs: django_settings_module: ${{ inputs.django_settings_module }} use_autoflake: ${{ inputs.use_autoflake }} use_bandit: ${{ inputs.use_bandit }} + use_black: ${{ inputs.use_black }} use_flake8: ${{ inputs.use_flake8 }} + use_isort: ${{ inputs.use_isort }} use_pylint: ${{ inputs.use_pylint }} + use_ruff_formatter: ${{ inputs.use_ruff_formatter }} + use_ruff_linter: ${{ inputs.use_ruff_linter }} - name: Create dev requirements file uses: ./.github/actions/python_requirements/create_dev_requirements_file @@ -416,7 +428,15 @@ jobs: - name: Run linters uses: ./.github/actions/python_linter - if: inputs.use_black || inputs.use_isort || inputs.use_flake8 || inputs.use_pylint || inputs.use_bandit || inputs.use_autoflake + if: > + inputs.use_black || + inputs.use_isort || + inputs.use_flake8 || + inputs.use_pylint || + inputs.use_bandit || + inputs.use_autoflake || + inputs.use_ruff_formatter || + inputs.use_ruff_linter with: working_directory: ${{ inputs.working_directory }} use_black: ${{ inputs.use_black }} @@ -425,6 +445,8 @@ jobs: use_pylint: ${{ inputs.use_pylint }} use_bandit: ${{ inputs.use_bandit }} use_autoflake: ${{ inputs.use_autoflake }} + use_ruff_formatter: ${{ inputs.use_ruff_formatter }} + use_ruff_linter: ${{ inputs.use_ruff_linter }} - name: Run CodeQL if: inputs.run_codeql diff --git a/.github/workflows/pull_request_automation.yml b/.github/workflows/pull_request_automation.yml index 7433a96..fc6a62e 100644 --- a/.github/workflows/pull_request_automation.yml +++ b/.github/workflows/pull_request_automation.yml @@ -62,6 +62,8 @@ jobs: use_pylint: true use_bandit: false use_autoflake: true + use_ruff_formatter: false + use_ruff_linter: true run_codeql: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c845ce3..9697a09 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,3 +43,12 @@ repos: hooks: - id: autoflake args: ["-i", "--remove-all-unused-imports", "--remove-unused-variables", "--ignore-init-module-imports", "--ignore-pass-statements"] + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.7 + hooks: + - id: ruff-format + args: ["--config", "./.github/configurations/python_linters/.ruff.toml"] + - id: ruff + name: ruff-lint + args: ["--config", "./.github/configurations/python_linters/.ruff.toml"] diff --git a/CHANGELOG.md b/CHANGELOG.md index c1fdbe5..d32056d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,11 @@ * Added "release.yml" action to to push containers to AWS ECR * Added *create_apt_cache.yaml* workflow to cache APT requirements each time a commit is pushed on selected branch and **when the requirements file has changed**. * Added documentation. +* Added "Ruff" to the list of available Python linters. #### Bugfix * Updated python linters also in '_python.yml' workflow (missing from previous release) * Explicitly disabled `xpack.security` in Elasticsearch container, since it is enabled by default in newer versions of Elasticsearch +* Added missing inputs for "create_linter_requirements_file" action. #### Changes * Deprecation of license check table-headers * Updated Python linters: diff --git a/actions/python_linter/action.yml b/actions/python_linter/action.yml index 8c285e0..1bd4637 100644 --- a/actions/python_linter/action.yml +++ b/actions/python_linter/action.yml @@ -5,6 +5,12 @@ inputs: description: Directory that must be run against the linters required: true + use_autoflake: + description: Use autoflake + required: true + use_bandit: + description: Use bandit linter + required: true use_black: description: Use black formatter required: true @@ -17,11 +23,11 @@ inputs: use_pylint: description: Use pylint linter required: true - use_bandit: - description: Use bandit linter + use_ruff_formatter: + description: Use ruff formatter required: true - use_autoflake: - description: Use autoflake + use_ruff_linter: + description: Use ruff linter required: true runs: @@ -66,11 +72,9 @@ runs: else echo "Skipping isort linter" fi - working-directory: ${{ inputs.working_directory }} shell: bash - - name: bandit run: | if [[ ${{inputs.use_bandit }} != 'false' ]]; then @@ -78,7 +82,6 @@ runs: else echo "Skipping bandit linter" fi - working-directory: ${{ inputs.working_directory }} shell: bash @@ -90,4 +93,24 @@ runs: echo "Skipping autoflake" fi working-directory: ${{ inputs.working_directory }} + shell: bash + + - name: ruff formatter + run: | + if [[ ${{ inputs.use_ruff_formatter }} != 'false' ]]; then + ruff format --config ${GITHUB_WORKSPACE}/.github/configurations/python_linters/.ruff.toml --diff . + else + echo "Skipping ruff formatter" + fi + working-directory: ${{ inputs.working_directory }} + shell: bash + + - name: ruff linter + run: | + if [[ ${{ inputs.use_ruff_linter }} != 'false' ]]; then + ruff check --config ${GITHUB_WORKSPACE}/.github/configurations/python_linters/.ruff.toml . + else + echo "Skipping ruff linter" + fi + working-directory: ${{ inputs.working_directory }} shell: bash \ No newline at end of file diff --git a/actions/python_requirements/create_linter_requirements_file/README.md b/actions/python_requirements/create_linter_requirements_file/README.md index 9be5aa9..fafbb9b 100644 --- a/actions/python_requirements/create_linter_requirements_file/README.md +++ b/actions/python_requirements/create_linter_requirements_file/README.md @@ -13,6 +13,7 @@ As of today only the following linters are supported: * `isort` * `pylint` * `pylint-django` +* `ruff` ## Documentation @@ -23,5 +24,9 @@ As of today only the following linters are supported: * **django_settings_module** - Optional - Path to the Django settings file. It's used to make GitHub action aware of Django presence. In the case of a Django project, `flake8-django` and `pylint-django`, may be used and hence they will be added to the newly created requirements file. **Be careful: if a relative path is used this will depend on *install_from*.** Defaults to empty strings, and hence **no Django settings file**. * **use_autoflake** - Optional - Flag to state whether to use or not `autoflake` linter. It defaults to false. * **use_bandit** - Optional - Flag to state whether to use or not `bandit` linter. It defaults to false. +* **use_black** - Optional - Flag to state whether to use `black` formatter. It defaults to false. * **use_flake8** - Optional - Flag to state whether to use or not `flake8` linter. It defaults to false. +* **use_isort** - Optional - Flag to state whether to use or not `isort` formatter. It defaults to false. * **use_pylint** - Optional - Flag to state whether to use or not `pylint` linter. It defaults to false. +* **use_ruff_formatter** - Optional - Flag to state whether to use `ruff` **formatter** (so without the linting). It defaults to false. +* **use_ruff_linter** - Optional - Flag to state whether to use `ruff` **linter** (so without the formatting). It defaults to false. diff --git a/actions/python_requirements/create_linter_requirements_file/action.yml b/actions/python_requirements/create_linter_requirements_file/action.yml index 7edb47f..b7ac092 100644 --- a/actions/python_requirements/create_linter_requirements_file/action.yml +++ b/actions/python_requirements/create_linter_requirements_file/action.yml @@ -17,13 +17,24 @@ inputs: use_bandit: description: Use bandit linter required: false + use_black: + description: Use black formatter + required: false use_flake8: description: Use flake8 linter required: false + use_isort: + description: Use isort formatter + required: false use_pylint: description: Use pylint linter required: false - + use_ruff_formatter: + description: Use ruff formatter + required: false + use_ruff_linter: + description: Use ruff linter + required: false runs: @@ -76,10 +87,15 @@ runs: if [[ '${{ inputs.use_bandit }}' != 'false' ]]; then check_linter_dependency_and_append_to_file "bandit" "$CI_REQUIREMENTS_LINTERS" fi + if [[ '${{ inputs.use_autoflake }}' != 'false' ]]; then check_linter_dependency_and_append_to_file "autoflake" "$CI_REQUIREMENTS_LINTERS" fi + if [[ '${{ inputs.use_ruff_formatter }}' != 'false' || '${{ inputs.use_ruff_linter }}' != 'false' ]]; then + check_linter_dependency_and_append_to_file "ruff" "$CI_REQUIREMENTS_LINTERS" + fi + if [[ -z '${{ inputs.project_linter_requirements_file }}' ]]; then cat $(echo ${{ inputs.project_linter_requirements_file }}) >> requirements-linters.txt fi diff --git a/configurations/python_linters/.ruff.toml b/configurations/python_linters/.ruff.toml new file mode 100644 index 0000000..601926e --- /dev/null +++ b/configurations/python_linters/.ruff.toml @@ -0,0 +1,51 @@ +# Top level settings +## Reference: https://docs.astral.sh/ruff/settings/#top-level + +extend-exclude = [ + ".github", + ".idea", + ".vscode", + "**/migrations/*" +] + +include = ["*.py"] + +indent-width = 4 + +line-length = 160 + +output-format = "full" + +respect-gitignore = false + +show-fixes = true + +target-version = "py312" + +# Format settings level +## Reference: https://docs.astral.sh/ruff/settings/#format +[format] + +docstring-code-format = true + +indent-style = "space" + +line-ending = "native" + +quote-style = "double" + +skip-magic-trailing-comma = false + +[lint] + +# Default + Isort +select = [ + "E4", + "E7", + "E9", + "F", + # Isort - https://docs.astral.sh/ruff/rules/#isort-i + "I" +] + +ignore = [ ] diff --git a/configurations/python_linters/requirements-linters.txt b/configurations/python_linters/requirements-linters.txt index d8e8a4c..5f7cdde 100644 --- a/configurations/python_linters/requirements-linters.txt +++ b/configurations/python_linters/requirements-linters.txt @@ -8,4 +8,5 @@ flake8-django @ git+https://github.com/terencehonles/flake8-django.git@a6e369e89 flake8~=7.1.2 isort~=6.0.1 pylint-django~=2.6.1 -pylint~=3.3.5 \ No newline at end of file +pylint~=3.3.5 +ruff~=0.12.7 \ No newline at end of file diff --git a/workflows/README.md b/workflows/README.md index 63ae6b8..258d5a1 100644 --- a/workflows/README.md +++ b/workflows/README.md @@ -133,10 +133,12 @@ It is composed of one job: * **max_timeout** - Optional - Maximum amount of time (in minutes) the workflow is allowed to run. By default, it is set to `30`. * **use_black** - Optional - Whether to use black formatter. By default, it is set to `false`. * **use_isort** - Optional - Whether to use isort formatter. By default, it is set to `false`. +* **use_ruff_formatter** - Optional - Whether to use ruff formatter. By default, it is set to `false`. * **use_autoflake** - Optional - Whether to use autoflake linter. By default, it is set to `false`. * **use_bandit** - Optional - Whether to use bandit linter. By default, it is set to `false`. * **use_flake8** - Optional - Whether to use flake8 linter. By default, it is set to `false`. * **use_pylint** - Optional - Whether to use pylint linter. By default, it is set to `false`. +* **use_ruff_linter** - Optional - Whether to use ruff linter. By default, it is set to `false`. * **use_coverage** - Optional - Whether to use coverage. By default, it is set to `false`. * **coverage_config_path** - Optional - Path to the coverage configuration file. By default, it is set to `.coveragerc`. * **upload_coverage** - Optional - Whether to upload coverage report to GitHub. To work, it needs *use_coverage* to be true. By default, it is set to `false`. diff --git a/workflows/_python.yml b/workflows/_python.yml index e2142b1..8c5c39f 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -50,6 +50,10 @@ on: description: Use isort formatter type: boolean required: false + use_ruff_formatter: + description: Use ruff formatter + type: boolean + required: false # Linters use_autoflake: @@ -68,6 +72,10 @@ on: description: Use pylint linter type: boolean required: false + use_ruff_linter: + description: Use ruff linter + type: boolean + required: false # Coverage configs use_coverage: @@ -306,8 +314,12 @@ jobs: django_settings_module: ${{ inputs.django_settings_module }} use_autoflake: ${{ inputs.use_autoflake }} use_bandit: ${{ inputs.use_bandit }} + use_black: ${{ inputs.use_black }} use_flake8: ${{ inputs.use_flake8 }} + use_isort: ${{ inputs.use_isort }} use_pylint: ${{ inputs.use_pylint }} + use_ruff_formatter: ${{ inputs.use_ruff_formatter }} + use_ruff_linter: ${{ inputs.use_ruff_linter }} - name: Create dev requirements file uses: ./.github/actions/python_requirements/create_dev_requirements_file @@ -416,7 +428,15 @@ jobs: - name: Run linters uses: ./.github/actions/python_linter - if: inputs.use_black || inputs.use_isort || inputs.use_flake8 || inputs.use_pylint || inputs.use_bandit || inputs.use_autoflake + if: > + inputs.use_black || + inputs.use_isort || + inputs.use_flake8 || + inputs.use_pylint || + inputs.use_bandit || + inputs.use_autoflake || + inputs.use_ruff_formatter || + inputs.use_ruff_linter with: working_directory: ${{ inputs.working_directory }} use_black: ${{ inputs.use_black }} @@ -425,6 +445,8 @@ jobs: use_pylint: ${{ inputs.use_pylint }} use_bandit: ${{ inputs.use_bandit }} use_autoflake: ${{ inputs.use_autoflake }} + use_ruff_formatter: ${{ inputs.use_ruff_formatter }} + use_ruff_linter: ${{ inputs.use_ruff_linter }} - name: Run CodeQL if: inputs.run_codeql diff --git a/workflows/pull_request_automation.yml b/workflows/pull_request_automation.yml index 7433a96..fc6a62e 100644 --- a/workflows/pull_request_automation.yml +++ b/workflows/pull_request_automation.yml @@ -62,6 +62,8 @@ jobs: use_pylint: true use_bandit: false use_autoflake: true + use_ruff_formatter: false + use_ruff_linter: true run_codeql: true