Fix broken or dangerous backquotes
Co-authored-by: Marco Borgeaud <89914223+marco-antognini-sonarsource@users.noreply.github.com>
This commit is contained in:
parent
7e46053974
commit
d3cfe19d7e
@ -39,7 +39,7 @@ tooling_tests_task:
|
|||||||
PYTHONPATH: .
|
PYTHONPATH: .
|
||||||
install_dependencies_script:
|
install_dependencies_script:
|
||||||
- cd rspec-tools
|
- cd rspec-tools
|
||||||
- pipenv install
|
- pipenv install --dev
|
||||||
- pipenv run pip install pytest pytest-cov
|
- pipenv run pip install pytest pytest-cov
|
||||||
tests_script:
|
tests_script:
|
||||||
- bash ci/fetch_branches.sh
|
- bash ci/fetch_branches.sh
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
# Validate the asciidoc environment directives in the given file(s).
|
|
||||||
# Errors are printed to the standard output stream.
|
|
||||||
#
|
|
||||||
# "ifdef" commands has to start the line without any leading spaces,
|
|
||||||
# as per asciidoc format.
|
|
||||||
#
|
|
||||||
# Only one form is allowed:
|
|
||||||
# ifdef::env-github,rspecator-view[]
|
|
||||||
#
|
|
||||||
# The closing command is:
|
|
||||||
# endif::env-github,rspecator-view[]
|
|
||||||
#
|
|
||||||
# It must be in the same file.
|
|
||||||
# Only one such environment is allowed per file.
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
VALID_IFDEF = "ifdef::env-github,rspecator-view[]"
|
|
||||||
VALID_ENDIF = "endif::env-github,rspecator-view[]"
|
|
||||||
|
|
||||||
|
|
||||||
class Checker:
|
|
||||||
def __init__(self, file: Path):
|
|
||||||
assert file.exists()
|
|
||||||
assert file.is_file()
|
|
||||||
|
|
||||||
self._file = file
|
|
||||||
self._is_env_open = False
|
|
||||||
self._has_env = False
|
|
||||||
self._is_valid = True
|
|
||||||
|
|
||||||
def process(self) -> bool:
|
|
||||||
content = self._file.read_text(encoding="utf-8")
|
|
||||||
lines = content.splitlines(keepends=False)
|
|
||||||
for line_index, line in enumerate(lines):
|
|
||||||
line_number = line_index + 1
|
|
||||||
if line.startswith("ifdef::"):
|
|
||||||
self._process_open(line_number, line)
|
|
||||||
if line.startswith("endif::"):
|
|
||||||
self._process_close(line_number, line)
|
|
||||||
|
|
||||||
if self._is_env_open:
|
|
||||||
self._on_error(len(lines), "The ifdef command is not closed.")
|
|
||||||
|
|
||||||
return self._is_valid
|
|
||||||
|
|
||||||
def _process_open(self, line_number: int, line: str):
|
|
||||||
if self._has_env:
|
|
||||||
self._on_error(line_number, "Only one ifdef command is allowed per file.")
|
|
||||||
|
|
||||||
if self._is_env_open:
|
|
||||||
self._on_error(line_number, "The previous ifdef command was not closed.")
|
|
||||||
|
|
||||||
self._has_env = True
|
|
||||||
self._is_env_open = True
|
|
||||||
|
|
||||||
# IDEs should be configured to properly display the description,
|
|
||||||
# not the other way around.
|
|
||||||
# "env-vscode" was used in the passed. Instead, user should be able to
|
|
||||||
# toggle the rspecator view based on their needs. Help these users migrate.
|
|
||||||
if "vscode" in line:
|
|
||||||
self._on_error(
|
|
||||||
line_number,
|
|
||||||
"Configure VS Code to display rspecator-view by setting the asciidoctor attribute.",
|
|
||||||
)
|
|
||||||
|
|
||||||
if line != VALID_IFDEF:
|
|
||||||
self._on_error(
|
|
||||||
line_number,
|
|
||||||
f'Incorrect asciidoc environment. "{VALID_IFDEF}" should be used instead.',
|
|
||||||
)
|
|
||||||
|
|
||||||
def _process_close(self, line_number: int, line: str):
|
|
||||||
if not self._is_env_open:
|
|
||||||
self._on_error(line_number, "Unexpected endif command.")
|
|
||||||
|
|
||||||
self._is_env_open = False
|
|
||||||
|
|
||||||
if line != VALID_ENDIF:
|
|
||||||
self._on_error(
|
|
||||||
line_number,
|
|
||||||
f'Incorrect endif command. "{VALID_ENDIF}" should be used instead.',
|
|
||||||
)
|
|
||||||
|
|
||||||
def _on_error(self, line_number: int, message: str):
|
|
||||||
print(f"{self._file}:{line_number} {message}")
|
|
||||||
self._is_valid = False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
files = sys.argv[1:]
|
|
||||||
if not files:
|
|
||||||
sys.exit("Missing input files")
|
|
||||||
|
|
||||||
valid = True
|
|
||||||
for file in files:
|
|
||||||
if not Checker(Path(file)).process():
|
|
||||||
valid = False
|
|
||||||
if not valid:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -72,30 +72,8 @@ do
|
|||||||
exit_code=1
|
exit_code=1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Make sure include:: clauses are always more than one line away from the previous content
|
# Add the full path of all adoc files that were affected for sanitization
|
||||||
# Detect includes stuck to the line before
|
find ~+/"${dir}" -name '*.adoc' >> all_asciidocs
|
||||||
find "$dir" -name "*.adoc" -execdir sh -c 'grep -Pzl "\S[ \t]*\ninclude::" $1 | xargs -r -I@ realpath "$PWD/@"' shell {} \; > stuck
|
|
||||||
# Detect includes stuck to the line after
|
|
||||||
find "$dir" -name "*.adoc" -execdir sh -c 'grep -Pzl "include::[^\[]+\[\]\n[ \t]*[^\n]" $1 | xargs -r -I@ realpath "$PWD/@"' shell {} \; >> stuck
|
|
||||||
if [ -s stuck ]; then
|
|
||||||
echo "ERROR: These adoc files contain an include that is stuck to other content."
|
|
||||||
echo "This may result in broken tags and other display issues."
|
|
||||||
echo "Make sure there is an empty line before and after each include:"
|
|
||||||
cat stuck
|
|
||||||
exit_code=1
|
|
||||||
fi
|
|
||||||
rm -f stuck
|
|
||||||
|
|
||||||
# Validate modified files' ifdef/endif commands.
|
|
||||||
find "${dir}" -name '*.adoc' \
|
|
||||||
-exec python3 "./ci/asciidoc_validation/validate_environment.py" '{}' '+' \
|
|
||||||
>validate_env_commands 2>&1
|
|
||||||
if [ -s validate_env_commands ]; then
|
|
||||||
echo "ERROR: Some ifdef/endif commands are misused."
|
|
||||||
cat validate_env_commands
|
|
||||||
exit_code=1
|
|
||||||
fi
|
|
||||||
rm -f validate_env_commands
|
|
||||||
|
|
||||||
for language in "${dir}"/*/
|
for language in "${dir}"/*/
|
||||||
do
|
do
|
||||||
@ -125,6 +103,18 @@ do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
cd rspec-tools
|
||||||
|
cat ../all_asciidocs | xargs pipenv run rspec-tools check-asciidoc >validate_asciidoc 2>&1
|
||||||
|
if [ -s validate_asciidoc ]; then
|
||||||
|
echo "ERROR: Invalid asciidoc description:"
|
||||||
|
cat validate_asciidoc
|
||||||
|
exit_code=1
|
||||||
|
fi
|
||||||
|
rm -f validate_asciidoc ../all_asciidocs
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Run asciidoctor and fail if a warning is emitted.
|
# Run asciidoctor and fail if a warning is emitted.
|
||||||
# Use the tmp_SXYZ_language.adoc files (see note above).
|
# Use the tmp_SXYZ_language.adoc files (see note above).
|
||||||
ADOC_COUNT=$(find rules -name "tmp*.adoc" | wc -l)
|
ADOC_COUNT=$(find rules -name "tmp*.adoc" | wc -l)
|
||||||
|
@ -17,7 +17,8 @@ slackclient = "*"
|
|||||||
[dev-packages]
|
[dev-packages]
|
||||||
pytest = ">=6.2.2"
|
pytest = ">=6.2.2"
|
||||||
mypy = ">=0.800"
|
mypy = ">=0.800"
|
||||||
rspec-tools = {editable = true, path = "."}
|
rspec-tools = {file = ".", editable = true}
|
||||||
|
pytest-snapshot = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.9"
|
python_version = "3.9"
|
||||||
|
371
rspec-tools/Pipfile.lock
generated
371
rspec-tools/Pipfile.lock
generated
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "ea9f240f8315f033a9883d447d2feb9b40fbad6bcbc336f404d47ebb6334e4c7"
|
"sha256": "5275bfce06cb7aea2422d149640dee6b7052a74e37d82fb02665df43d223005e"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
@ -106,6 +106,7 @@
|
|||||||
"sha256:fc37e9aef10a696a5a4474802930079ccfc14d9f9c10b4662169671ff034b7df",
|
"sha256:fc37e9aef10a696a5a4474802930079ccfc14d9f9c10b4662169671ff034b7df",
|
||||||
"sha256:fdee8405931b0615220e5ddf8cd7edd8592c606a8e4ca2a00704883c396e4479"
|
"sha256:fdee8405931b0615220e5ddf8cd7edd8592c606a8e4ca2a00704883c396e4479"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==3.8.6"
|
"version": "==3.8.6"
|
||||||
},
|
},
|
||||||
"aiosignal": {
|
"aiosignal": {
|
||||||
@ -113,6 +114,7 @@
|
|||||||
"sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc",
|
"sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc",
|
||||||
"sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"
|
"sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==1.3.1"
|
"version": "==1.3.1"
|
||||||
},
|
},
|
||||||
"appdirs": {
|
"appdirs": {
|
||||||
@ -127,6 +129,7 @@
|
|||||||
"sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f",
|
"sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f",
|
||||||
"sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"
|
"sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==4.0.3"
|
"version": "==4.0.3"
|
||||||
},
|
},
|
||||||
"attrs": {
|
"attrs": {
|
||||||
@ -134,6 +137,7 @@
|
|||||||
"sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04",
|
"sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04",
|
||||||
"sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"
|
"sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==23.1.0"
|
"version": "==23.1.0"
|
||||||
},
|
},
|
||||||
"beautifulsoup4": {
|
"beautifulsoup4": {
|
||||||
@ -141,6 +145,7 @@
|
|||||||
"sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da",
|
"sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da",
|
||||||
"sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"
|
"sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"
|
||||||
],
|
],
|
||||||
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==4.12.2"
|
"version": "==4.12.2"
|
||||||
},
|
},
|
||||||
"bs4": {
|
"bs4": {
|
||||||
@ -155,6 +160,7 @@
|
|||||||
"sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
|
"sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
|
||||||
"sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
|
"sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==2023.7.22"
|
"version": "==2023.7.22"
|
||||||
},
|
},
|
||||||
"cffi": {
|
"cffi": {
|
||||||
@ -212,102 +218,104 @@
|
|||||||
"sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956",
|
"sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956",
|
||||||
"sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"
|
"sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==1.16.0"
|
"version": "==1.16.0"
|
||||||
},
|
},
|
||||||
"charset-normalizer": {
|
"charset-normalizer": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843",
|
"sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5",
|
||||||
"sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786",
|
"sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93",
|
||||||
"sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e",
|
"sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a",
|
||||||
"sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8",
|
"sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d",
|
||||||
"sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4",
|
"sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c",
|
||||||
"sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa",
|
"sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1",
|
||||||
"sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d",
|
"sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58",
|
||||||
"sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82",
|
"sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2",
|
||||||
"sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7",
|
"sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557",
|
||||||
"sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895",
|
"sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147",
|
||||||
"sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d",
|
"sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041",
|
||||||
"sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a",
|
"sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2",
|
||||||
"sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382",
|
"sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2",
|
||||||
"sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678",
|
"sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7",
|
||||||
"sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b",
|
"sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296",
|
||||||
"sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e",
|
"sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690",
|
||||||
"sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741",
|
"sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67",
|
||||||
"sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4",
|
"sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57",
|
||||||
"sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596",
|
"sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597",
|
||||||
"sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9",
|
"sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846",
|
||||||
"sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69",
|
"sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b",
|
||||||
"sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c",
|
"sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97",
|
||||||
"sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77",
|
"sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c",
|
||||||
"sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13",
|
"sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62",
|
||||||
"sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459",
|
"sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa",
|
||||||
"sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e",
|
"sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f",
|
||||||
"sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7",
|
"sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e",
|
||||||
"sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908",
|
"sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821",
|
||||||
"sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a",
|
"sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3",
|
||||||
"sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f",
|
"sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4",
|
||||||
"sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8",
|
"sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb",
|
||||||
"sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482",
|
"sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727",
|
||||||
"sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d",
|
"sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514",
|
||||||
"sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d",
|
"sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d",
|
||||||
"sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545",
|
"sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761",
|
||||||
"sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34",
|
"sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55",
|
||||||
"sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86",
|
"sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f",
|
||||||
"sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6",
|
"sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c",
|
||||||
"sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe",
|
"sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034",
|
||||||
"sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e",
|
"sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6",
|
||||||
"sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc",
|
"sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae",
|
||||||
"sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7",
|
"sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1",
|
||||||
"sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd",
|
"sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14",
|
||||||
"sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c",
|
"sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1",
|
||||||
"sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557",
|
"sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228",
|
||||||
"sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a",
|
"sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708",
|
||||||
"sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89",
|
"sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48",
|
||||||
"sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078",
|
"sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f",
|
||||||
"sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e",
|
"sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5",
|
||||||
"sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4",
|
"sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f",
|
||||||
"sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403",
|
"sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4",
|
||||||
"sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0",
|
"sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8",
|
||||||
"sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89",
|
"sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff",
|
||||||
"sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115",
|
"sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61",
|
||||||
"sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9",
|
"sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b",
|
||||||
"sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05",
|
"sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97",
|
||||||
"sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a",
|
"sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b",
|
||||||
"sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec",
|
"sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605",
|
||||||
"sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56",
|
"sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728",
|
||||||
"sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38",
|
"sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d",
|
||||||
"sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479",
|
"sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c",
|
||||||
"sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c",
|
"sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf",
|
||||||
"sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e",
|
"sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673",
|
||||||
"sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd",
|
"sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1",
|
||||||
"sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186",
|
"sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b",
|
||||||
"sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455",
|
"sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41",
|
||||||
"sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c",
|
"sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8",
|
||||||
"sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65",
|
"sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f",
|
||||||
"sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78",
|
"sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4",
|
||||||
"sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287",
|
"sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008",
|
||||||
"sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df",
|
"sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9",
|
||||||
"sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43",
|
"sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5",
|
||||||
"sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1",
|
"sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f",
|
||||||
"sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7",
|
"sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e",
|
||||||
"sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989",
|
"sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273",
|
||||||
"sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a",
|
"sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45",
|
||||||
"sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63",
|
"sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e",
|
||||||
"sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884",
|
"sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656",
|
||||||
"sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649",
|
"sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e",
|
||||||
"sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810",
|
"sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c",
|
||||||
"sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828",
|
"sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2",
|
||||||
"sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4",
|
"sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72",
|
||||||
"sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2",
|
"sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056",
|
||||||
"sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd",
|
"sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397",
|
||||||
"sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5",
|
"sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42",
|
||||||
"sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe",
|
"sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd",
|
||||||
"sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293",
|
"sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3",
|
||||||
"sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e",
|
"sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213",
|
||||||
"sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e",
|
"sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf",
|
||||||
"sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"
|
"sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"
|
||||||
],
|
],
|
||||||
"version": "==3.3.0"
|
"markers": "python_full_version >= '3.7.0'",
|
||||||
|
"version": "==3.3.1"
|
||||||
},
|
},
|
||||||
"click": {
|
"click": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -315,41 +323,43 @@
|
|||||||
"sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
|
"sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==8.1.7"
|
"version": "==8.1.7"
|
||||||
},
|
},
|
||||||
"cryptography": {
|
"cryptography": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67",
|
"sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf",
|
||||||
"sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311",
|
"sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84",
|
||||||
"sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8",
|
"sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e",
|
||||||
"sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13",
|
"sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8",
|
||||||
"sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143",
|
"sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7",
|
||||||
"sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f",
|
"sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1",
|
||||||
"sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829",
|
"sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88",
|
||||||
"sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd",
|
"sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86",
|
||||||
"sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397",
|
"sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179",
|
||||||
"sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac",
|
"sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81",
|
||||||
"sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d",
|
"sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20",
|
||||||
"sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a",
|
"sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548",
|
||||||
"sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839",
|
"sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d",
|
||||||
"sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e",
|
"sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d",
|
||||||
"sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6",
|
"sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5",
|
||||||
"sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9",
|
"sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1",
|
||||||
"sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860",
|
"sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147",
|
||||||
"sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca",
|
"sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936",
|
||||||
"sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91",
|
"sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797",
|
||||||
"sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d",
|
"sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696",
|
||||||
"sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714",
|
"sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72",
|
||||||
"sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb",
|
"sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da",
|
||||||
"sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f"
|
"sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723"
|
||||||
],
|
],
|
||||||
"version": "==41.0.4"
|
"version": "==41.0.5"
|
||||||
},
|
},
|
||||||
"deprecated": {
|
"deprecated": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c",
|
"sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c",
|
||||||
"sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"
|
"sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==1.2.14"
|
"version": "==1.2.14"
|
||||||
},
|
},
|
||||||
"frozenlist": {
|
"frozenlist": {
|
||||||
@ -416,6 +426,7 @@
|
|||||||
"sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1",
|
"sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1",
|
||||||
"sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"
|
"sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==1.4.0"
|
"version": "==1.4.0"
|
||||||
},
|
},
|
||||||
"fs": {
|
"fs": {
|
||||||
@ -428,24 +439,27 @@
|
|||||||
},
|
},
|
||||||
"gitdb": {
|
"gitdb": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a",
|
"sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4",
|
||||||
"sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"
|
"sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"
|
||||||
],
|
],
|
||||||
"version": "==4.0.10"
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==4.0.11"
|
||||||
},
|
},
|
||||||
"gitpython": {
|
"gitpython": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:5f4c4187de49616d710a77e98ddf17b4782060a1788df441846bddefbb89ab33",
|
"sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4",
|
||||||
"sha256:f9b9ddc0761c125d5780eab2d64be4873fc6817c2899cbcb34b02344bdc7bc54"
|
"sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==3.1.37"
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==3.1.40"
|
||||||
},
|
},
|
||||||
"idna": {
|
"idna": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
|
"sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
|
||||||
"sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
|
"sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==3.4"
|
"version": "==3.4"
|
||||||
},
|
},
|
||||||
"jsonschema": {
|
"jsonschema": {
|
||||||
@ -454,6 +468,7 @@
|
|||||||
"sha256:ec84cc37cfa703ef7cd4928db24f9cb31428a5d0fa77747b8b51a847458e0bbf"
|
"sha256:ec84cc37cfa703ef7cd4928db24f9cb31428a5d0fa77747b8b51a847458e0bbf"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==4.19.1"
|
"version": "==4.19.1"
|
||||||
},
|
},
|
||||||
"jsonschema-specifications": {
|
"jsonschema-specifications": {
|
||||||
@ -461,6 +476,7 @@
|
|||||||
"sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1",
|
"sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1",
|
||||||
"sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"
|
"sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==2023.7.1"
|
"version": "==2023.7.1"
|
||||||
},
|
},
|
||||||
"multidict": {
|
"multidict": {
|
||||||
@ -540,6 +556,7 @@
|
|||||||
"sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d",
|
"sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d",
|
||||||
"sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"
|
"sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==6.0.4"
|
"version": "==6.0.4"
|
||||||
},
|
},
|
||||||
"pycparser": {
|
"pycparser": {
|
||||||
@ -555,13 +572,18 @@
|
|||||||
"sha256:ecf12c2809c44147bce63b047b3d2e9dac8a41b63e90fcb263c703f64936b97c"
|
"sha256:ecf12c2809c44147bce63b047b3d2e9dac8a41b63e90fcb263c703f64936b97c"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==2.1.1"
|
"version": "==2.1.1"
|
||||||
},
|
},
|
||||||
"pyjwt": {
|
"pyjwt": {
|
||||||
|
"extras": [
|
||||||
|
"crypto"
|
||||||
|
],
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de",
|
"sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de",
|
||||||
"sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"
|
"sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==2.8.0"
|
"version": "==2.8.0"
|
||||||
},
|
},
|
||||||
"pynacl": {
|
"pynacl": {
|
||||||
@ -577,6 +599,7 @@
|
|||||||
"sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b",
|
"sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b",
|
||||||
"sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"
|
"sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==1.5.0"
|
"version": "==1.5.0"
|
||||||
},
|
},
|
||||||
"python-dateutil": {
|
"python-dateutil": {
|
||||||
@ -584,6 +607,7 @@
|
|||||||
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
|
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
|
||||||
"sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
|
"sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==2.8.2"
|
"version": "==2.8.2"
|
||||||
},
|
},
|
||||||
"referencing": {
|
"referencing": {
|
||||||
@ -591,6 +615,7 @@
|
|||||||
"sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf",
|
"sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf",
|
||||||
"sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"
|
"sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==0.30.2"
|
"version": "==0.30.2"
|
||||||
},
|
},
|
||||||
"requests": {
|
"requests": {
|
||||||
@ -598,6 +623,7 @@
|
|||||||
"sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
|
"sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
|
||||||
"sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
|
"sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==2.31.0"
|
"version": "==2.31.0"
|
||||||
},
|
},
|
||||||
"rpds-py": {
|
"rpds-py": {
|
||||||
@ -702,17 +728,27 @@
|
|||||||
"sha256:f0f17f2ce0f3529177a5fff5525204fad7b43dd437d017dd0317f2746773443d",
|
"sha256:f0f17f2ce0f3529177a5fff5525204fad7b43dd437d017dd0317f2746773443d",
|
||||||
"sha256:f4e56860a5af16a0fcfa070a0a20c42fbb2012eed1eb5ceeddcc7f8079214281"
|
"sha256:f4e56860a5af16a0fcfa070a0a20c42fbb2012eed1eb5ceeddcc7f8079214281"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==0.10.6"
|
"version": "==0.10.6"
|
||||||
},
|
},
|
||||||
"rspec-tools": {
|
"rspec-tools": {
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"path": "."
|
"path": "."
|
||||||
},
|
},
|
||||||
|
"setuptools": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87",
|
||||||
|
"sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==68.2.2"
|
||||||
|
},
|
||||||
"six": {
|
"six": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==1.16.0"
|
"version": "==1.16.0"
|
||||||
},
|
},
|
||||||
"slackapi": {
|
"slackapi": {
|
||||||
@ -728,6 +764,7 @@
|
|||||||
"sha256:ab79fefb5412d0595bc01d2f195a787597f2a617b6766562932ab9ffbe5cb173"
|
"sha256:ab79fefb5412d0595bc01d2f195a787597f2a617b6766562932ab9ffbe5cb173"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==2.9.4"
|
"version": "==2.9.4"
|
||||||
},
|
},
|
||||||
"smmap": {
|
"smmap": {
|
||||||
@ -735,6 +772,7 @@
|
|||||||
"sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62",
|
"sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62",
|
||||||
"sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"
|
"sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==5.0.1"
|
"version": "==5.0.1"
|
||||||
},
|
},
|
||||||
"soupsieve": {
|
"soupsieve": {
|
||||||
@ -742,6 +780,7 @@
|
|||||||
"sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690",
|
"sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690",
|
||||||
"sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"
|
"sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==2.5"
|
"version": "==2.5"
|
||||||
},
|
},
|
||||||
"typing-extensions": {
|
"typing-extensions": {
|
||||||
@ -749,14 +788,16 @@
|
|||||||
"sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0",
|
"sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0",
|
||||||
"sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"
|
"sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==4.8.0"
|
"version": "==4.8.0"
|
||||||
},
|
},
|
||||||
"urllib3": {
|
"urllib3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2",
|
"sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84",
|
||||||
"sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564"
|
"sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"
|
||||||
],
|
],
|
||||||
"version": "==2.0.6"
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==2.0.7"
|
||||||
},
|
},
|
||||||
"wrapt": {
|
"wrapt": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -836,6 +877,7 @@
|
|||||||
"sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559",
|
"sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559",
|
||||||
"sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"
|
"sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==1.15.0"
|
"version": "==1.15.0"
|
||||||
},
|
},
|
||||||
"yarl": {
|
"yarl": {
|
||||||
@ -915,6 +957,7 @@
|
|||||||
"sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78",
|
"sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78",
|
||||||
"sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"
|
"sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==1.9.2"
|
"version": "==1.9.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -932,46 +975,49 @@
|
|||||||
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
|
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
|
||||||
"sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
|
"sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==2.0.0"
|
"version": "==2.0.0"
|
||||||
},
|
},
|
||||||
"mypy": {
|
"mypy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:091f53ff88cb093dcc33c29eee522c087a438df65eb92acd371161c1f4380ff0",
|
"sha256:19f905bcfd9e167159b3d63ecd8cb5e696151c3e59a1742e79bc3bcb540c42c7",
|
||||||
"sha256:1a69db3018b87b3e6e9dd28970f983ea6c933800c9edf8c503c3135b3274d5ad",
|
"sha256:21a1ad938fee7d2d96ca666c77b7c494c3c5bd88dff792220e1afbebb2925b5e",
|
||||||
"sha256:24f3de8b9e7021cd794ad9dfbf2e9fe3f069ff5e28cb57af6f873ffec1cb0425",
|
"sha256:40b1844d2e8b232ed92e50a4bd11c48d2daa351f9deee6c194b83bf03e418b0c",
|
||||||
"sha256:31eba8a7a71f0071f55227a8057468b8d2eb5bf578c8502c7f01abaec8141b2f",
|
"sha256:41697773aa0bf53ff917aa077e2cde7aa50254f28750f9b88884acea38a16169",
|
||||||
"sha256:3c8835a07b8442da900db47ccfda76c92c69c3a575872a5b764332c4bacb5a0a",
|
"sha256:49ae115da099dcc0922a7a895c1eec82c1518109ea5c162ed50e3b3594c71208",
|
||||||
"sha256:3df87094028e52766b0a59a3e46481bb98b27986ed6ded6a6cc35ecc75bb9182",
|
"sha256:4c46b51de523817a0045b150ed11b56f9fff55f12b9edd0f3ed35b15a2809de0",
|
||||||
"sha256:49499cf1e464f533fc45be54d20a6351a312f96ae7892d8e9f1708140e27ce41",
|
"sha256:4cbe68ef919c28ea561165206a2dcb68591c50f3bcf777932323bc208d949cf1",
|
||||||
"sha256:4c192445899c69f07874dabda7e931b0cc811ea055bf82c1ababf358b9b2a72c",
|
"sha256:4d01c00d09a0be62a4ca3f933e315455bde83f37f892ba4b08ce92f3cf44bcc1",
|
||||||
"sha256:4f3d27537abde1be6d5f2c96c29a454da333a2a271ae7d5bc7110e6d4b7beb3f",
|
"sha256:59a0d7d24dfb26729e0a068639a6ce3500e31d6655df8557156c51c1cb874ce7",
|
||||||
"sha256:7469545380dddce5719e3656b80bdfbb217cfe8dbb1438532d6abc754b828fed",
|
"sha256:68351911e85145f582b5aa6cd9ad666c8958bcae897a1bfda8f4940472463c45",
|
||||||
"sha256:7807a2a61e636af9ca247ba8494031fb060a0a744b9fee7de3a54bed8a753323",
|
"sha256:7274b0c57737bd3476d2229c6389b2ec9eefeb090bbaf77777e9d6b1b5a9d143",
|
||||||
"sha256:856bad61ebc7d21dbc019b719e98303dc6256cec6dcc9ebb0b214b81d6901bd8",
|
"sha256:81af8adaa5e3099469e7623436881eff6b3b06db5ef75e6f5b6d4871263547e5",
|
||||||
"sha256:89513ddfda06b5c8ebd64f026d20a61ef264e89125dc82633f3c34eeb50e7d60",
|
"sha256:82e469518d3e9a321912955cc702d418773a2fd1e91c651280a1bda10622f02f",
|
||||||
"sha256:8e0db37ac4ebb2fee7702767dfc1b773c7365731c22787cb99f507285014fcaf",
|
"sha256:8b27958f8c76bed8edaa63da0739d76e4e9ad4ed325c814f9b3851425582a3cd",
|
||||||
"sha256:971104bcb180e4fed0d7bd85504c9036346ab44b7416c75dd93b5c8c6bb7e28f",
|
"sha256:8c223fa57cb154c7eab5156856c231c3f5eace1e0bed9b32a24696b7ba3c3245",
|
||||||
"sha256:9e1589ca150a51d9d00bb839bfeca2f7a04f32cd62fad87a847bc0818e15d7dc",
|
"sha256:8f57e6b6927a49550da3d122f0cb983d400f843a8a82e65b3b380d3d7259468f",
|
||||||
"sha256:9f8464ed410ada641c29f5de3e6716cbdd4f460b31cf755b2af52f2d5ea79ead",
|
"sha256:925cd6a3b7b55dfba252b7c4561892311c5358c6b5a601847015a1ad4eb7d332",
|
||||||
"sha256:ab98b8f6fdf669711f3abe83a745f67f50e3cbaea3998b90e8608d2b459fd566",
|
"sha256:a43ef1c8ddfdb9575691720b6352761f3f53d85f1b57d7745701041053deff30",
|
||||||
"sha256:b19006055dde8a5425baa5f3b57a19fa79df621606540493e5e893500148c72f",
|
"sha256:a8032e00ce71c3ceb93eeba63963b864bf635a18f6c0c12da6c13c450eedb183",
|
||||||
"sha256:c69051274762cccd13498b568ed2430f8d22baa4b179911ad0c1577d336ed849",
|
"sha256:b96ae2c1279d1065413965c607712006205a9ac541895004a1e0d4f281f2ff9f",
|
||||||
"sha256:d2dad072e01764823d4b2f06bc7365bb1d4b6c2f38c4d42fade3c8d45b0b4b67",
|
"sha256:bb8ccb4724f7d8601938571bf3f24da0da791fe2db7be3d9e79849cb64e0ae85",
|
||||||
"sha256:dccd850a2e3863891871c9e16c54c742dba5470f5120ffed8152956e9e0a5e13",
|
"sha256:bbaf4662e498c8c2e352da5f5bca5ab29d378895fa2d980630656178bd607c46",
|
||||||
"sha256:e28d7b221898c401494f3b77db3bac78a03ad0a0fff29a950317d87885c655d2",
|
"sha256:cfd13d47b29ed3bbaafaff7d8b21e90d827631afda134836962011acb5904b71",
|
||||||
"sha256:e4b7a99275a61aa22256bab5839c35fe8a6887781862471df82afb4b445daae6",
|
"sha256:d4473c22cc296425bbbce7e9429588e76e05bc7342da359d6520b6427bf76660",
|
||||||
"sha256:eb7ff4007865833c470a601498ba30462b7374342580e2346bf7884557e40531",
|
"sha256:d8fbb68711905f8912e5af474ca8b78d077447d8f3918997fecbf26943ff3cbb",
|
||||||
"sha256:f8598307150b5722854f035d2e70a1ad9cc3c72d392c34fffd8c66d888c90f17",
|
"sha256:e5012e5cc2ac628177eaac0e83d622b2dd499e28253d4107a08ecc59ede3fc2c",
|
||||||
"sha256:fea451a3125bf0bfe716e5d7ad4b92033c471e4b5b3e154c67525539d14dc15a"
|
"sha256:eb4f18589d196a4cbe5290b435d135dee96567e07c2b2d43b5c4621b6501531a"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.6.0"
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==1.6.1"
|
||||||
},
|
},
|
||||||
"mypy-extensions": {
|
"mypy-extensions": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d",
|
"sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d",
|
||||||
"sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"
|
"sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==1.0.0"
|
"version": "==1.0.0"
|
||||||
},
|
},
|
||||||
"packaging": {
|
"packaging": {
|
||||||
@ -979,6 +1025,7 @@
|
|||||||
"sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5",
|
"sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5",
|
||||||
"sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
|
"sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==23.2"
|
"version": "==23.2"
|
||||||
},
|
},
|
||||||
"pluggy": {
|
"pluggy": {
|
||||||
@ -986,15 +1033,26 @@
|
|||||||
"sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12",
|
"sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12",
|
||||||
"sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"
|
"sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==1.3.0"
|
"version": "==1.3.0"
|
||||||
},
|
},
|
||||||
"pytest": {
|
"pytest": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002",
|
"sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac",
|
||||||
"sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"
|
"sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==7.4.2"
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==7.4.3"
|
||||||
|
},
|
||||||
|
"pytest-snapshot": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4b9fe1c21c868fe53a545e4e3184d36bc1c88946e3f5c1d9dd676962a9b3d4ab",
|
||||||
|
"sha256:c7013c3abc3e860f9feff899f8b4debe3708650d8d8242a61bf2625ff64db7f3"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
|
"version": "==0.9.0"
|
||||||
},
|
},
|
||||||
"rspec-tools": {
|
"rspec-tools": {
|
||||||
"editable": true,
|
"editable": true,
|
||||||
@ -1013,6 +1071,7 @@
|
|||||||
"sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0",
|
"sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0",
|
||||||
"sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"
|
"sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==4.8.0"
|
"version": "==4.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ Usage
|
|||||||
.See all commands
|
.See all commands
|
||||||
[source,sh]
|
[source,sh]
|
||||||
----
|
----
|
||||||
$ rspec-tools --help
|
$ pipenv run rspec-tools --help
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ $ pipenv install --dev -e .
|
|||||||
.Run tests
|
.Run tests
|
||||||
[source,sh]
|
[source,sh]
|
||||||
----
|
----
|
||||||
$ pytest
|
$ pipenv run pytest
|
||||||
----
|
----
|
||||||
|
|
||||||
.Fixtures
|
.Fixtures
|
||||||
|
@ -18,6 +18,7 @@ from rspec_tools.validation.description import (validate_subsections,
|
|||||||
validate_section_levels,
|
validate_section_levels,
|
||||||
validate_section_names,
|
validate_section_names,
|
||||||
validate_source_language)
|
validate_source_language)
|
||||||
|
from rspec_tools.validation.sanitize_asciidoc import sanitize_asciidoc
|
||||||
from rspec_tools.validation.metadata import validate_rule_metadata
|
from rspec_tools.validation.metadata import validate_rule_metadata
|
||||||
|
|
||||||
|
|
||||||
@ -87,6 +88,17 @@ def validate_rules_metadata(rules):
|
|||||||
_fatal_error(f"Validation failed due to {error_counter} errors out of {len(rules)} analyzed rules")
|
_fatal_error(f"Validation failed due to {error_counter} errors out of {len(rules)} analyzed rules")
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command()
|
||||||
|
@click.argument('files', nargs=-1, required=True)
|
||||||
|
def check_asciidoc(files):
|
||||||
|
'''Sanitize the AsciiDoc description.'''
|
||||||
|
error_counter = 0
|
||||||
|
for file in files:
|
||||||
|
error_counter += sanitize_asciidoc(Path(file))
|
||||||
|
if error_counter > 0:
|
||||||
|
_fatal_error(f"Validation of the asciidoc description failed due to {error_counter} errors")
|
||||||
|
|
||||||
|
|
||||||
VALIDATORS = [validate_subsections,
|
VALIDATORS = [validate_subsections,
|
||||||
validate_section_names,
|
validate_section_names,
|
||||||
validate_section_levels,
|
validate_section_levels,
|
||||||
|
254
rspec-tools/rspec_tools/validation/sanitize_asciidoc.py
Normal file
254
rspec-tools/rspec_tools/validation/sanitize_asciidoc.py
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
""" Ensure the asciidoc code for a rule description follows best practices
|
||||||
|
|
||||||
|
Checks are:
|
||||||
|
* "ifdef"/"endif" blocks should be well-formed for RSPEC
|
||||||
|
* Inline code with backquotes is correctly escaped and balanced
|
||||||
|
* Include commands are not appended to other code
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
VALID_IFDEF = "ifdef::env-github,rspecator-view[]"
|
||||||
|
VALID_ENDIF = "endif::env-github,rspecator-view[]"
|
||||||
|
|
||||||
|
VARIABLE_DECL = re.compile(r':\w+: ')
|
||||||
|
|
||||||
|
INCLUDE = re.compile(r'include::')
|
||||||
|
|
||||||
|
FORMATTING_CHARS = ['_', r'\*', r'\#']
|
||||||
|
WORD_FORMATTING_CHARS = [r'\~', r'\^']
|
||||||
|
|
||||||
|
# If the formatting char is repeated twice, it can go anywhere
|
||||||
|
UNCONSTRAINED_FORMATTING = '|'.join(x + x for x in FORMATTING_CHARS)
|
||||||
|
# Single formatting char are dangerous at the beginning of a word
|
||||||
|
FORMATTING_OPENING = '|'.join(r'(\W|^)' + x + r'\w' for x in FORMATTING_CHARS)
|
||||||
|
# Single formatting char are dangerous at the end of a word
|
||||||
|
FORMATTING_CLOSING = '|'.join(r'\w' + x + r'(\W|$)' for x in FORMATTING_CHARS)
|
||||||
|
# Word formatting is broken by spaces so we look for things like `#word#`
|
||||||
|
WORD_FORMATTING = "|".join(x + r'\S+' + x for x in WORD_FORMATTING_CHARS)
|
||||||
|
|
||||||
|
# We combine all the matchers
|
||||||
|
NEED_PROTECTION = re.compile('('
|
||||||
|
f'{UNCONSTRAINED_FORMATTING}|'
|
||||||
|
f'{FORMATTING_OPENING}|'
|
||||||
|
f'{FORMATTING_CLOSING}|'
|
||||||
|
f'{WORD_FORMATTING}'
|
||||||
|
')')
|
||||||
|
|
||||||
|
# There is a regex trick here:
|
||||||
|
# We want to stop the search if there is a backquote
|
||||||
|
# We do that by matching backquote OR the closing passthrough
|
||||||
|
# Then we'll ignore any match of backquote
|
||||||
|
CLOSE_CONSTRAINED_PASSTHROUGH = re.compile(r'`|((?<!\s)\+(?=`))')
|
||||||
|
|
||||||
|
CLOSE_CONSTRAINED_BACKQUOTE = re.compile(r'`(?!\w)')
|
||||||
|
CLOSE_UNCONSTRAINED_BACKQUOTE = re.compile('``')
|
||||||
|
|
||||||
|
PASSTHROUGH_MACRO_TEXT = r'pass:\w*\[(\\\]|[^\]])*\]'
|
||||||
|
|
||||||
|
PASSTHROUGH_MACRO = re.compile(PASSTHROUGH_MACRO_TEXT)
|
||||||
|
|
||||||
|
# There is a regex trick here:
|
||||||
|
# We want to skip passthrough macros, to not find pass:[``whatever``]
|
||||||
|
# We do that by matching
|
||||||
|
# * EITHER passthrough macros including their ignored backquotes
|
||||||
|
# * OR backquotes
|
||||||
|
# Then we'll ignore any match of PASSTHROUGH_MACRO
|
||||||
|
BACKQUOTE = re.compile(PASSTHROUGH_MACRO_TEXT + r'|(?P<backquote>(``+)|(?<![\\\w])(`)(?!\s))')
|
||||||
|
|
||||||
|
def close_passthrough(count, pos, line):
|
||||||
|
"""Find the end of a passthrough block marked by *count* plus signs"""
|
||||||
|
while count > 0:
|
||||||
|
# `+++a++` will display '+a' in case of inbalance, we try to find the biggest closing block
|
||||||
|
if count == 1:
|
||||||
|
if not line[pos + count].isspace() and line[pos - 1] == '`':
|
||||||
|
#constrained '+'. It is a passthrough only if it is directly around text and surrounded by backquotes: `+Some Content+`
|
||||||
|
close_pattern = CLOSE_CONSTRAINED_PASSTHROUGH
|
||||||
|
else:
|
||||||
|
return pos
|
||||||
|
else:
|
||||||
|
close_pattern = re.compile('(' + r'\+' * count + ')')
|
||||||
|
end = close_pattern.search(line, pos + count)
|
||||||
|
if end and end.group(1):
|
||||||
|
return end.end()
|
||||||
|
count -= 1
|
||||||
|
return pos
|
||||||
|
|
||||||
|
|
||||||
|
def skip_passthrough_macro(line, pos):
|
||||||
|
'''If this is a passthrough macro, skip to the end'''
|
||||||
|
if line[pos] == 'p':
|
||||||
|
pm = PASSTHROUGH_MACRO.match(line, pos)
|
||||||
|
if pm:
|
||||||
|
return pm.end()
|
||||||
|
return pos
|
||||||
|
|
||||||
|
|
||||||
|
def skip_passthrough_plus(line, pos):
|
||||||
|
'''If this is a passthrough +, skip to the end'''
|
||||||
|
if line[pos] == '+':
|
||||||
|
count = 1
|
||||||
|
while pos + count < len(line) and line[pos + count] == '+':
|
||||||
|
count += 1
|
||||||
|
return close_passthrough(count, pos, line)
|
||||||
|
return pos
|
||||||
|
|
||||||
|
|
||||||
|
def close_inline_block(line: str, pos: int, closing_pattern: re.Pattern[str]):
|
||||||
|
"""Find the end of an inline block started with *pattern*"""
|
||||||
|
content = ""
|
||||||
|
while pos < len(line):
|
||||||
|
pos = skip_passthrough_macro(line, pos)
|
||||||
|
pos = skip_passthrough_plus(line, pos)
|
||||||
|
if closing_pattern.match(line, pos):
|
||||||
|
return pos, content
|
||||||
|
content += line[pos]
|
||||||
|
pos += 1
|
||||||
|
return -1, content
|
||||||
|
|
||||||
|
|
||||||
|
class Sanitizer:
|
||||||
|
def __init__(self, file: Path):
|
||||||
|
assert file.exists()
|
||||||
|
assert file.is_file()
|
||||||
|
|
||||||
|
self._file = file
|
||||||
|
self._is_env_open = False
|
||||||
|
self._has_env = False
|
||||||
|
self._error_count = 0
|
||||||
|
self._is_inside_code = False
|
||||||
|
self._empty_line = True
|
||||||
|
self._previous_line_was_include = False
|
||||||
|
|
||||||
|
def process(self) -> bool:
|
||||||
|
content = self._file.read_text(encoding="utf-8")
|
||||||
|
lines = content.splitlines(keepends=False)
|
||||||
|
for line_index, line in enumerate(lines):
|
||||||
|
if self._is_inside_code:
|
||||||
|
if line == '----':
|
||||||
|
self._is_inside_code = False
|
||||||
|
continue
|
||||||
|
if line == '----':
|
||||||
|
self._is_inside_code = True
|
||||||
|
continue
|
||||||
|
line_number = line_index + 1
|
||||||
|
if line.startswith("ifdef::"):
|
||||||
|
self._process_open_ifdef(line_number, line)
|
||||||
|
elif line.startswith("endif::"):
|
||||||
|
self._process_close_ifdef(line_number, line)
|
||||||
|
elif not line.strip():
|
||||||
|
self._empty_line = True
|
||||||
|
else:
|
||||||
|
self._process_description(line_number, line)
|
||||||
|
self._empty_line = False
|
||||||
|
|
||||||
|
if self._is_env_open:
|
||||||
|
self._on_error(len(lines), "An ifdef command is opened but never closed.")
|
||||||
|
|
||||||
|
return self._error_count
|
||||||
|
|
||||||
|
def _process_open_ifdef(self, line_number: int, line: str):
|
||||||
|
if self._has_env:
|
||||||
|
message = "Only one ifdef command is allowed per file."
|
||||||
|
if self._is_env_open:
|
||||||
|
message += "\nThe previous ifdef command was not closed."
|
||||||
|
self._on_error(line_number, message)
|
||||||
|
|
||||||
|
self._has_env = True
|
||||||
|
self._is_env_open = True
|
||||||
|
|
||||||
|
# IDEs should be configured to properly display the description,
|
||||||
|
# not the other way around.
|
||||||
|
# "env-vscode" was used in the passed. Instead, user should be able to
|
||||||
|
# toggle the rspecator view based on their needs. Help these users migrate.
|
||||||
|
if "vscode" in line:
|
||||||
|
self._on_error(
|
||||||
|
line_number,
|
||||||
|
"Configure VS Code to display rspecator-view by setting the asciidoctor attribute.",
|
||||||
|
)
|
||||||
|
elif line != VALID_IFDEF:
|
||||||
|
self._on_error(
|
||||||
|
line_number,
|
||||||
|
f'Incorrect asciidoc environment. "{VALID_IFDEF}" should be used instead.',
|
||||||
|
)
|
||||||
|
|
||||||
|
def _process_close_ifdef(self, line_number: int, line: str):
|
||||||
|
if not self._is_env_open:
|
||||||
|
self._on_error(line_number, "Unexpected endif command.")
|
||||||
|
|
||||||
|
self._is_env_open = False
|
||||||
|
|
||||||
|
if line != VALID_ENDIF:
|
||||||
|
self._on_error(
|
||||||
|
line_number,
|
||||||
|
f'Incorrect endif command. "{VALID_ENDIF}" should be used instead.',
|
||||||
|
)
|
||||||
|
|
||||||
|
def _process_description(self, line_number: int, line: str):
|
||||||
|
if VARIABLE_DECL.match(line):
|
||||||
|
return
|
||||||
|
if self._previous_line_was_include and not self._empty_line:
|
||||||
|
self._on_error(line_number - 1, '''An empty line is missing after the include.
|
||||||
|
This may result in broken tags and other display issues.
|
||||||
|
Make sure there are always empty lines before and after each include''')
|
||||||
|
if INCLUDE.match(line):
|
||||||
|
self._previous_line_was_include = True
|
||||||
|
if not self._empty_line:
|
||||||
|
self._on_error(line_number, '''An empty line is missing before the include.
|
||||||
|
This may result in broken tags and other display issues.
|
||||||
|
Make sure there are always empty lines before and after each include''')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self._previous_line_was_include = False
|
||||||
|
pos = 0
|
||||||
|
res = BACKQUOTE.search(line, pos)
|
||||||
|
# We filter out matches for passthrough. See comment near the BACKQUOTE declaration
|
||||||
|
while res and res.group('backquote'):
|
||||||
|
pos = self._check_inlined_code(line_number, res.end(), line, res.group('backquote'))
|
||||||
|
res = BACKQUOTE.search(line, pos)
|
||||||
|
|
||||||
|
def _check_inlined_code(self, line_number: int, pos: int, line: str, opening_pattern: str):
|
||||||
|
if len(opening_pattern) > 2:
|
||||||
|
# Part of the backquotes are displayed as backquotes.
|
||||||
|
self._on_error(line_number, 'Use "++" to isolate the backquotes you want to display from the ones that should be interpreted by AsciiDoc.')
|
||||||
|
return pos
|
||||||
|
elif len(opening_pattern) == 2:
|
||||||
|
closing_pattern = CLOSE_UNCONSTRAINED_BACKQUOTE
|
||||||
|
else:
|
||||||
|
closing_pattern = CLOSE_CONSTRAINED_BACKQUOTE
|
||||||
|
|
||||||
|
content_end, content = close_inline_block(line, pos, closing_pattern)
|
||||||
|
if content_end < 0:
|
||||||
|
message='Unbalanced code inlining tags.'
|
||||||
|
if len(opening_pattern) == 1:
|
||||||
|
message += '''
|
||||||
|
If you are trying to write inline code that is glued to text without a space,
|
||||||
|
you need to use double backquotes:
|
||||||
|
> Replace all `reference`s.
|
||||||
|
Will not display correctly. You need to write:
|
||||||
|
> Replace all ``reference``s.
|
||||||
|
'''
|
||||||
|
self._on_error(line_number, message)
|
||||||
|
return len(line)
|
||||||
|
pos = content_end + len(opening_pattern)
|
||||||
|
if NEED_PROTECTION.search(content):
|
||||||
|
self._on_error (line_number, f'''
|
||||||
|
Using backquotes does not protect against asciidoc interpretation. Starting or
|
||||||
|
ending a word with '*', '#', '_' or having two of them consecutively will
|
||||||
|
trigger unintended behavior with the rest of the text.
|
||||||
|
Use ``++{content}++`` to avoid that.
|
||||||
|
If you really want to have formatting inside your code, you can write
|
||||||
|
``pass:n[{content}]``
|
||||||
|
''')
|
||||||
|
return pos
|
||||||
|
return pos
|
||||||
|
|
||||||
|
def _on_error(self, line_number: int, message: str):
|
||||||
|
print(f"{self._file}:{line_number} {message}")
|
||||||
|
self._error_count += 1
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_asciidoc(file_path: Path):
|
||||||
|
"""Called by the CLI"""
|
||||||
|
return Sanitizer(file_path).process()
|
@ -20,6 +20,17 @@ def mockinvalidrules():
|
|||||||
return Path(__file__).parent.joinpath('resources', 'invalid-rules')
|
return Path(__file__).parent.joinpath('resources', 'invalid-rules')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mockinvalidasciidoc():
|
||||||
|
'''Provides a path to test asciidoc resources.'''
|
||||||
|
return Path(__file__).parent.joinpath('resources', 'invalid-asciidoc')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mockasciidoc():
|
||||||
|
'''Provides a path to test asciidoc resources.'''
|
||||||
|
return Path(__file__).parent.joinpath('resources', 'asciidoc')
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def git_config():
|
def git_config():
|
||||||
'''Create a mock git configuration.'''
|
'''Create a mock git configuration.'''
|
||||||
|
35
rspec-tools/tests/resources/asciidoc/valid.adoc
Normal file
35
rspec-tools/tests/resources/asciidoc/valid.adoc
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
This is a file with `valid inlined code`.
|
||||||
|
It's using ``unconstrained tag``s.
|
||||||
|
It has ``++**protected tags**++``
|
||||||
|
It escapes `++`++` backquotes
|
||||||
|
it can use `\` or `+`
|
||||||
|
|
||||||
|
Plays well with beginning and end of lines:
|
||||||
|
`++`++`
|
||||||
|
|
||||||
|
Mix of passthrough and plusses `+{plus}##+{plus}+`
|
||||||
|
|
||||||
|
:var: ``Variables are not interpreted`
|
||||||
|
|
||||||
|
{var}
|
||||||
|
|
||||||
|
We can use passthrough macros `pass:[__like that__]`
|
||||||
|
|
||||||
|
Or we can use passthrough macros `as a pass:[__part__] of the code`.
|
||||||
|
|
||||||
|
The pass:[can also be outside `__the backquotes__`]
|
||||||
|
|
||||||
|
The pass:[``++Can have __ [escaped brackets\] __ ++``]
|
||||||
|
|
||||||
|
[source,python]
|
||||||
|
----
|
||||||
|
# We don't care about `in the code
|
||||||
|
----
|
||||||
|
|
||||||
|
We can have a sole ` surrounded by spaces
|
||||||
|
|
||||||
|
This file does not exist but we only check that the include is well placed:
|
||||||
|
|
||||||
|
include::everything_ok.adoc[]
|
||||||
|
|
||||||
|
For `constrained*format` we don't raise an issue unless `+*it's+ at the beginning or end of a +~word~+`.
|
@ -0,0 +1,5 @@
|
|||||||
|
Some description
|
||||||
|
|
||||||
|
Now we try to close and ifdef that was never opened.
|
||||||
|
|
||||||
|
endif::env-github,rspecator-view[]
|
@ -0,0 +1,4 @@
|
|||||||
|
# Header
|
||||||
|
|
||||||
|
include::somefile.adoc[]
|
||||||
|
* content just after
|
@ -0,0 +1,2 @@
|
|||||||
|
# Header
|
||||||
|
include::somefile.adoc[]
|
@ -0,0 +1 @@
|
|||||||
|
$PATH/close_unopened_ifdef.adoc:5 Unexpected endif command.
|
@ -0,0 +1,3 @@
|
|||||||
|
$PATH/include_stuck_after.adoc:3 An empty line is missing after the include.
|
||||||
|
This may result in broken tags and other display issues.
|
||||||
|
Make sure there are always empty lines before and after each include
|
@ -0,0 +1,3 @@
|
|||||||
|
$PATH/include_stuck_before.adoc:2 An empty line is missing before the include.
|
||||||
|
This may result in broken tags and other display issues.
|
||||||
|
Make sure there are always empty lines before and after each include
|
@ -0,0 +1 @@
|
|||||||
|
$PATH/triple_backquotes.adoc:1 Use "++" to isolate the backquotes you want to display from the ones that should be interpreted by AsciiDoc.
|
@ -0,0 +1 @@
|
|||||||
|
$PATH/two_ifdef.adoc:9 Only one ifdef command is allowed per file.
|
@ -0,0 +1,2 @@
|
|||||||
|
$PATH/two_ifdef_unclosed.adoc:7 Only one ifdef command is allowed per file.
|
||||||
|
The previous ifdef command was not closed.
|
@ -0,0 +1,6 @@
|
|||||||
|
$PATH/two_stuck_includes.adoc:3 An empty line is missing after the include.
|
||||||
|
This may result in broken tags and other display issues.
|
||||||
|
Make sure there are always empty lines before and after each include
|
||||||
|
$PATH/two_stuck_includes.adoc:4 An empty line is missing before the include.
|
||||||
|
This may result in broken tags and other display issues.
|
||||||
|
Make sure there are always empty lines before and after each include
|
@ -0,0 +1 @@
|
|||||||
|
$PATH/unbalanced_double_backquotes.adoc:2 Unbalanced code inlining tags.
|
@ -0,0 +1,7 @@
|
|||||||
|
$PATH/unbalanced_single_backquotes.adoc:1 Unbalanced code inlining tags.
|
||||||
|
If you are trying to write inline code that is glued to text without a space,
|
||||||
|
you need to use double backquotes:
|
||||||
|
> Replace all `reference`s.
|
||||||
|
Will not display correctly. You need to write:
|
||||||
|
> Replace all ``reference``s.
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
$PATH/unclosed_ifdef.adoc:6 An ifdef command is opened but never closed.
|
@ -0,0 +1,32 @@
|
|||||||
|
$PATH/unprotected_formatting.adoc:1
|
||||||
|
Using backquotes does not protect against asciidoc interpretation. Starting or
|
||||||
|
ending a word with '*', '#', '_' or having two of them consecutively will
|
||||||
|
trigger unintended behavior with the rest of the text.
|
||||||
|
Use ``++*careful++`` to avoid that.
|
||||||
|
If you really want to have formatting inside your code, you can write
|
||||||
|
``pass:n[*careful]``
|
||||||
|
|
||||||
|
$PATH/unprotected_formatting.adoc:3
|
||||||
|
Using backquotes does not protect against asciidoc interpretation. Starting or
|
||||||
|
ending a word with '*', '#', '_' or having two of them consecutively will
|
||||||
|
trigger unintended behavior with the rest of the text.
|
||||||
|
Use ``++unpro**tected++`` to avoid that.
|
||||||
|
If you really want to have formatting inside your code, you can write
|
||||||
|
``pass:n[unpro**tected]``
|
||||||
|
|
||||||
|
$PATH/unprotected_formatting.adoc:5
|
||||||
|
Using backquotes does not protect against asciidoc interpretation. Starting or
|
||||||
|
ending a word with '*', '#', '_' or having two of them consecutively will
|
||||||
|
trigger unintended behavior with the rest of the text.
|
||||||
|
Use ``++~flags~++`` to avoid that.
|
||||||
|
If you really want to have formatting inside your code, you can write
|
||||||
|
``pass:n[~flags~]``
|
||||||
|
|
||||||
|
$PATH/unprotected_formatting.adoc:7
|
||||||
|
Using backquotes does not protect against asciidoc interpretation. Starting or
|
||||||
|
ending a word with '*', '#', '_' or having two of them consecutively will
|
||||||
|
trigger unintended behavior with the rest of the text.
|
||||||
|
Use ``++_problems_++`` to avoid that.
|
||||||
|
If you really want to have formatting inside your code, you can write
|
||||||
|
``pass:n[_problems_]``
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
$PATH/unprotected_formatting_with_plusses.adoc:1
|
||||||
|
Using backquotes does not protect against asciidoc interpretation. Starting or
|
||||||
|
ending a word with '*', '#', '_' or having two of them consecutively will
|
||||||
|
trigger unintended behavior with the rest of the text.
|
||||||
|
Use ``++This is not + ##protected## +++`` to avoid that.
|
||||||
|
If you really want to have formatting inside your code, you can write
|
||||||
|
``pass:n[This is not + ##protected## +]``
|
||||||
|
|
@ -0,0 +1,2 @@
|
|||||||
|
$PATH/vscode_ifdef.adoc:3 Configure VS Code to display rspecator-view by setting the asciidoctor attribute.
|
||||||
|
$PATH/vscode_ifdef.adoc:7 Incorrect endif command. "endif::env-github,rspecator-view[]" should be used instead.
|
@ -0,0 +1,7 @@
|
|||||||
|
$PATH/wrong_constrained_passthrough.adoc:1 Unbalanced code inlining tags.
|
||||||
|
If you are trying to write inline code that is glued to text without a space,
|
||||||
|
you need to use double backquotes:
|
||||||
|
> Replace all `reference`s.
|
||||||
|
Will not display correctly. You need to write:
|
||||||
|
> Replace all ``reference``s.
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
$PATH/wrong_endif.adoc:7 Incorrect endif command. "endif::env-github,rspecator-view[]" should be used instead.
|
@ -0,0 +1 @@
|
|||||||
|
$PATH/wrong_ifdef.adoc:3 Incorrect asciidoc environment. "ifdef::env-github,rspecator-view[]" should be used instead.
|
@ -0,0 +1,3 @@
|
|||||||
|
We don't like people using three backquotes to display one in monospace ```
|
||||||
|
|
||||||
|
Instead they should write `++`++`
|
13
rspec-tools/tests/resources/invalid-asciidoc/two_ifdef.adoc
Normal file
13
rspec-tools/tests/resources/invalid-asciidoc/two_ifdef.adoc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Some description
|
||||||
|
|
||||||
|
ifdef::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
A first ifdef block
|
||||||
|
|
||||||
|
endif::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
ifdef::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
This second ifdef should not be there
|
||||||
|
|
||||||
|
endif::env-github,rspecator-view[]
|
@ -0,0 +1,11 @@
|
|||||||
|
Some description
|
||||||
|
|
||||||
|
ifdef::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
A first ifdef block
|
||||||
|
|
||||||
|
ifdef::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
This second ifdef should not be there
|
||||||
|
|
||||||
|
endif::env-github,rspecator-view[]
|
@ -0,0 +1,6 @@
|
|||||||
|
# Header
|
||||||
|
|
||||||
|
include::somefile.adoc[]
|
||||||
|
include::someotherfile.adoc[]
|
||||||
|
|
||||||
|
* Other content
|
@ -0,0 +1,4 @@
|
|||||||
|
This is a test for double
|
||||||
|
backquotes``next to text
|
||||||
|
|
||||||
|
We shouldn't raise on this``double backquote usage``.
|
@ -0,0 +1,3 @@
|
|||||||
|
Some text with `unbalanced`backquotes
|
||||||
|
Some other text where ` is used correctly. Shouldn't rais
|
||||||
|
`inlined code with single quotes`
|
@ -0,0 +1,6 @@
|
|||||||
|
Some content followed by an ifdef
|
||||||
|
|
||||||
|
ifdef::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
This ifdef should be valid
|
||||||
|
But then we don't close the block
|
@ -0,0 +1,7 @@
|
|||||||
|
we should be `*careful`
|
||||||
|
|
||||||
|
of `unpro**tected`
|
||||||
|
|
||||||
|
formatting `~flags~`
|
||||||
|
|
||||||
|
They can create `_problems_`.
|
@ -0,0 +1 @@
|
|||||||
|
Some content and `This is not + ##protected## +`
|
@ -0,0 +1,7 @@
|
|||||||
|
Some content followed by an ifdef
|
||||||
|
|
||||||
|
ifdef::env-github,rspecator-view,env-vscode[]
|
||||||
|
|
||||||
|
This ifdef is wrong because we add vscode flags in it
|
||||||
|
|
||||||
|
endif::env-github,rspecator-view,env-vscode[]
|
@ -0,0 +1 @@
|
|||||||
|
Constrained pass-through are broken by backquotes: `+`+`
|
@ -0,0 +1,7 @@
|
|||||||
|
Some content followed by an ifdef
|
||||||
|
|
||||||
|
ifdef::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
This ifdef is wrong because we don't close it with the expected values
|
||||||
|
|
||||||
|
endif::test,rspecator-view[]
|
@ -0,0 +1,7 @@
|
|||||||
|
Some content followed by an ifdef
|
||||||
|
|
||||||
|
ifdef::mytest,rspecator-view[]
|
||||||
|
|
||||||
|
This ifdef is wrong because we don't open it with the expected values
|
||||||
|
|
||||||
|
endif::env-github,rspecator-view[]
|
43
rspec-tools/tests/validation/test_asciidoc_sanitization.py
Normal file
43
rspec-tools/tests/validation/test_asciidoc_sanitization.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from rspec_tools.validation.sanitize_asciidoc import sanitize_asciidoc
|
||||||
|
|
||||||
|
|
||||||
|
def relative_output(capsys, path: Path):
|
||||||
|
return capsys.readouterr().out.replace(str(path), '$PATH')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('invalid_file,expected_count', [('unbalanced_single_backquotes', 1),
|
||||||
|
('unbalanced_double_backquotes', 1),
|
||||||
|
('triple_backquotes', 1),
|
||||||
|
('unprotected_formatting', 4),
|
||||||
|
('unprotected_formatting_with_plusses', 1),
|
||||||
|
('wrong_constrained_passthrough', 1),
|
||||||
|
('unclosed_ifdef', 1),
|
||||||
|
('close_unopened_ifdef', 1),
|
||||||
|
('two_ifdef', 1),
|
||||||
|
('two_ifdef_unclosed', 1),
|
||||||
|
('vscode_ifdef', 2),
|
||||||
|
('wrong_ifdef', 1),
|
||||||
|
('wrong_endif', 1),
|
||||||
|
('include_stuck_before', 1),
|
||||||
|
('include_stuck_after', 1),
|
||||||
|
('two_stuck_includes', 2)
|
||||||
|
])
|
||||||
|
def test_need_sanitation(mockinvalidasciidoc: Path, invalid_file, expected_count, capsys, snapshot):
|
||||||
|
'''Check that we detect needs for sanitation.'''
|
||||||
|
name_path = Path(invalid_file)
|
||||||
|
adoc = mockinvalidasciidoc / name_path.with_suffix('.adoc')
|
||||||
|
expected = mockinvalidasciidoc / 'snapshots' / name_path.with_suffix('.txt')
|
||||||
|
assert sanitize_asciidoc(adoc) == expected_count
|
||||||
|
snapshot.snapshot_dir = mockinvalidasciidoc / 'snapshots'
|
||||||
|
snapshot.assert_match(relative_output(capsys, mockinvalidasciidoc), expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_correctly_sanitized(mockasciidoc: Path):
|
||||||
|
'''Check that we raise no issue on correctly sanitized asciidoc'''
|
||||||
|
name_path = Path('valid')
|
||||||
|
adoc = mockasciidoc / name_path.with_suffix('.adoc')
|
||||||
|
assert sanitize_asciidoc(adoc) == 0
|
@ -15,7 +15,7 @@ When throwing an exception, it is therefore recommended to throw the most specif
|
|||||||
To fix this issue, make sure to throw specific exceptions that are relevant to the context in which they arise. It is recommended to either:
|
To fix this issue, make sure to throw specific exceptions that are relevant to the context in which they arise. It is recommended to either:
|
||||||
|
|
||||||
* Throw a subtype of `Exception` that already exists in the Standard PHP Library. For instance ``++InvalidArgumentException++`` could be raised when an unexpected argument is provided to a function.
|
* Throw a subtype of `Exception` that already exists in the Standard PHP Library. For instance ``++InvalidArgumentException++`` could be raised when an unexpected argument is provided to a function.
|
||||||
* Define a custom exception type that derives from `++Exception++`` or one of its subclasses.
|
* Define a custom exception type that derives from ``++Exception++`` or one of its subclasses.
|
||||||
|
|
||||||
=== Code examples
|
=== Code examples
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ global using System.Net.Sockets; // Compliant by exception
|
|||||||
|
|
||||||
Unnecessary `using` directives are ignored in ASP.NET Core projects in the following files:
|
Unnecessary `using` directives are ignored in ASP.NET Core projects in the following files:
|
||||||
|
|
||||||
* `_Imports.razor`
|
* ``++_Imports.razor++``
|
||||||
* `_ViewImports.cshtml`
|
* ``++_ViewImports.cshtml++``
|
||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ include::../message.adoc[]
|
|||||||
(visible only on this page)
|
(visible only on this page)
|
||||||
|
|
||||||
=== on 3 Mar 2020, 17:27:45 Nicolas Harraudeau wrote:
|
=== on 3 Mar 2020, 17:27:45 Nicolas Harraudeau wrote:
|
||||||
Note: There is no need to create issues for \``++raise++`` statements because:
|
Note: There is no need to create issues for ``++raise++`` statements because:
|
||||||
|
|
||||||
* there might be a good reason to raise an exception (Ex: cannot release resource)
|
* there might be a good reason to raise an exception (Ex: cannot release resource)
|
||||||
* python will link the new exception and the old exception automatically:
|
* python will link the new exception and the old exception automatically:
|
||||||
|
@ -37,13 +37,13 @@ For the parameters of the rule, the following rules are applied:
|
|||||||
|
|
||||||
* `?` matches a single character
|
* `?` matches a single character
|
||||||
* `*` matches zero or more characters
|
* `*` matches zero or more characters
|
||||||
* `**` matches zero or more packages
|
* ``++**++`` matches zero or more packages
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
* `java.internal.InternalClass` will match only `InternalClass` class.
|
* `java.internal.InternalClass` will match only `InternalClass` class.
|
||||||
* `java.internal.*` will match any member of `java.internal` package.
|
* ``++java.internal.*++`` will match any member of `java.internal` package.
|
||||||
* `java.internal.**` same as above, but including sub-packages.
|
* ``++java.internal.**++`` same as above, but including sub-packages.
|
||||||
|
|
||||||
=== Code examples
|
=== Code examples
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ include::../description.adoc[]
|
|||||||
|
|
||||||
=== Exceptions
|
=== Exceptions
|
||||||
|
|
||||||
To prevent generating some false-positives, literals having less than 10 characters are excluded as well as literals matching `/^\w*$/`.
|
To prevent generating some false-positives, literals having less than 10 characters are excluded as well as literals matching ``++/^\w*$/++``.
|
||||||
String literals inside import/export statements and JSX attributes are also ignored.
|
String literals inside import/export statements and JSX attributes are also ignored.
|
||||||
The same goes for statement-like string literals, e.g. `'use strict';`.
|
The same goes for statement-like string literals, e.g. `'use strict';`.
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ Specifically, deallocation should correspond to allocation as per the table belo
|
|||||||
|Allocation | Deallocation
|
|Allocation | Deallocation
|
||||||
|`p = new T();` | `delete p;`
|
|`p = new T();` | `delete p;`
|
||||||
|`+p = new T[5];+` | `+delete[] p;+`
|
|`+p = new T[5];+` | `+delete[] p;+`
|
||||||
|`p = malloc(sizeof(int)*5);` | `free(p);`
|
|``++p = malloc(sizeof(int)*5);++`` | `free(p);`
|
||||||
|============================================
|
|============================================
|
||||||
|
|
||||||
=== What is the potential impact?
|
=== What is the potential impact?
|
||||||
@ -62,7 +62,7 @@ delete[] p; // Noncompliant: expect array cookie
|
|||||||
|
|
||||||
|
|
||||||
If you need allocate memory in a custom `T::operator new(std::size_t)`,
|
If you need allocate memory in a custom `T::operator new(std::size_t)`,
|
||||||
you should use `void* ::operator new(std::size_t)` and not `free()`.
|
you should use ``++void* ::operator new(std::size_t)++`` and not `free()`.
|
||||||
|
|
||||||
Note that `::operator new` is still not compatible with `free()`:
|
Note that `::operator new` is still not compatible with `free()`:
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
A ``++switch++`` statement is a control flow statement that allows you to execute different blocks of code based on the value of an expression. It provides a more concise way to handle multiple conditions compared to using multiple ``++if-else++`` statements.
|
A ``++switch++`` statement is a control flow statement that allows you to execute different blocks of code based on the value of an expression. It provides a more concise way to handle multiple conditions compared to using multiple ``++if-else++`` statements.
|
||||||
|
|
||||||
If you only have a single condition to check, using an ``++if++``` statement is simpler and more concise. ``++switch++`` statements are designed for handling multiple cases, so using them for a single condition can be overkill and less readable.
|
If you only have a single condition to check, using an ``++if++`` statement is simpler and more concise. ``++switch++`` statements are designed for handling multiple cases, so using them for a single condition can be overkill and less readable.
|
||||||
|
|
||||||
This rule raises an issue when a ``++switch++`` statement has only one ``++case++`` clause and possibly a ``++default`` one.
|
This rule raises an issue when a ``++switch++`` statement has only one ``++case++`` clause and possibly a ``++default++`` one.
|
||||||
|
|
||||||
[source,javascript,diff-id=1,diff-type=noncompliant]
|
[source,javascript,diff-id=1,diff-type=noncompliant]
|
||||||
----
|
----
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
This rule raises an issue when the `Collections.EMPTY_*` fields are used instead of the `Collections.empty*()` methods.
|
This rule raises an issue when the ``++Collections.EMPTY_*++`` fields are used instead of the ``++Collections.empty*()++`` methods.
|
||||||
|
|
||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Use:
|
|||||||
- `Collections.emptySet()` instead of `Collections.EMPTY_SET`
|
- `Collections.emptySet()` instead of `Collections.EMPTY_SET`
|
||||||
- `Collections.emptyMap()` instead of `Collections.EMPTY_MAP`
|
- `Collections.emptyMap()` instead of `Collections.EMPTY_MAP`
|
||||||
|
|
||||||
In addition, there are variants of `Collections.empty*()` available also for other collection interfaces,
|
In addition, there are variants of ``++Collections.empty*()++`` available also for other collection interfaces,
|
||||||
such as `Collections.emptyIterator()`, `Collections.emptyNavigableMap()`, `Collections.emptySortedSet()`.
|
such as `Collections.emptyIterator()`, `Collections.emptyNavigableMap()`, `Collections.emptySortedSet()`.
|
||||||
|
|
||||||
=== Code examples
|
=== Code examples
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
Using a function in PHP with the same name as the nesting class was historically used to declare a class constructor.
|
Using a function in PHP with the same name as the nesting class was historically used to declare a class constructor.
|
||||||
However, as of PHP 8.0.0, this declaration is discouraged and will provoke an `E_DEPRECATED` error, albeit it functions as a constructor.
|
However, as of PHP 8.0.0, this declaration is discouraged and will provoke an `E_DEPRECATED` error, albeit it functions as a constructor.
|
||||||
|
|
||||||
Instead, users should explicitly define the constructor by declaring a `\__construct(...)` function.
|
Instead, users should explicitly define the constructor by declaring a ``++__construct(...)++`` function.
|
||||||
However, if both styles are present in the same class, PHP will treat the `__construct` function as the class constructor, which can cause unintended behavior.
|
However, if both styles are present in the same class, PHP will treat the ``++__construct++`` function as the class constructor, which can cause unintended behavior.
|
||||||
|
|
||||||
Adhering to this convention improves readability and maintainability by ensuring that the constructor declaration is named uniformly throughout the codebase.
|
Adhering to this convention improves readability and maintainability by ensuring that the constructor declaration is named uniformly throughout the codebase.
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ When constructing an object of type C, the following occurs:
|
|||||||
|
|
||||||
* The sub-object of type `A` is constructed.
|
* The sub-object of type `A` is constructed.
|
||||||
* The sub-object of type `B` is constructed.
|
* The sub-object of type `B` is constructed.
|
||||||
** The constructor `B::B()` is called, during this call, `*this` is considered as being of type `B`.
|
** The constructor ``++B::B()++`` is called, during this call, ``++*this++`` is considered as being of type `B`.
|
||||||
** The function `B::f()` is called.
|
** The function `B::f()` is called.
|
||||||
** The function `A::g()` is called.
|
** The function `A::g()` is called.
|
||||||
* The object of type `C` is constructed.
|
* The object of type `C` is constructed.
|
||||||
|
@ -30,7 +30,7 @@ for word in words:
|
|||||||
|
|
||||||
Python will raise a `SyntaxError` when `break` or `continue` are used outside of `for` or `while` loops.
|
Python will raise a `SyntaxError` when `break` or `continue` are used outside of `for` or `while` loops.
|
||||||
|
|
||||||
If the goal is to interrupt the main program flow, `quit()`, `exit()`, `os._exit()` and `sys.exit()` are the preferred way.
|
If the goal is to interrupt the main program flow, `quit()`, `exit()`, ``++os._exit()++`` and `sys.exit()` are the preferred way.
|
||||||
|
|
||||||
=== Code examples
|
=== Code examples
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ Using the same value on both sides of a binary operator is a code defect. In the
|
|||||||
The following are ignored:
|
The following are ignored:
|
||||||
|
|
||||||
* The expression `1 << 1`
|
* The expression `1 << 1`
|
||||||
* When an increment or decrement operator is used, ex: ``*p{plus}{plus} == *p{plus}{plus}``
|
* When an increment or decrement operator is used, ex: ``+++*p++ == *p+++++``
|
||||||
* Bitwise operators `|, &, ^`
|
* Bitwise operators `|, &, ^`
|
||||||
* Arithmetic operators `+, *`
|
* Arithmetic operators `+, *`
|
||||||
* Assignment operators `=, +=, *=`
|
* Assignment operators `=, +=, *=`
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
* It is not part of the standard, which prevents its use in some contexts.
|
* It is not part of the standard, which prevents its use in some contexts.
|
||||||
* Even if it is supported by virtually all compilers, since its behavior is not defined, it may differ between compilers, especially for some corner cases when determining if two files are identical (for instance, in the presence of symbolic links).
|
* Even if it is supported by virtually all compilers, since its behavior is not defined, it may differ between compilers, especially for some corner cases when determining if two files are identical (for instance, in the presence of symbolic links).
|
||||||
* Its semantic is slightly different from the semantic of an include guard. For instance, if a file is duplicated in two different locations, `#pragma once` will not prevent multiple inclusion of this file.
|
* Its semantic is slightly different from the semantic of an include guard. For instance, if a file is duplicated in two different locations, ``++#pragma once++`` will not prevent multiple inclusion of this file.
|
||||||
|
|
||||||
Note: There used to be a build performance improvement when using `#pragma once` instead of an include guard because naive implementations of include guards need to parse the full file to get the `#endif` matching the `#if`. But most modern compilers specifically detect the include guard pattern and use a dedicated optimization that makes it about as fast as `#pragma once`.
|
Note: There used to be a build performance improvement when using ``++#pragma once++`` instead of an include guard because naive implementations of include guards need to parse the full file to get the ``++#endif++`` matching the ``++#if++``. But most modern compilers specifically detect the include guard pattern and use a dedicated optimization that makes it about as fast as ``++#pragma once++``.
|
||||||
|
|
||||||
|
|
||||||
=== Noncompliant code example
|
=== Noncompliant code example
|
||||||
|
@ -5,7 +5,7 @@ include::../why.adoc[]
|
|||||||
The rule ignores
|
The rule ignores
|
||||||
|
|
||||||
* Initializations to `-1`, `0`, `1`, `undefined`, `[]`, `{}`, `true`, `false` and `""`.
|
* Initializations to `-1`, `0`, `1`, `undefined`, `[]`, `{}`, `true`, `false` and `""`.
|
||||||
* Variables that start with an underscore (e.g. \'`_unused`') are ignored.
|
* Variables that start with an underscore (e.g. ``++_unused++``) are ignored.
|
||||||
* Assignment of `null` is ignored because it is sometimes used to help garbage collection
|
* Assignment of `null` is ignored because it is sometimes used to help garbage collection
|
||||||
* Increment and decrement expressions are ignored because they are often used idiomatically instead of `x+1`
|
* Increment and decrement expressions are ignored because they are often used idiomatically instead of `x+1`
|
||||||
* This rule also ignores variables declared with object destructuring using rest syntax (used to exclude some properties from object)
|
* This rule also ignores variables declared with object destructuring using rest syntax (used to exclude some properties from object)
|
||||||
|
@ -39,7 +39,7 @@ Within the JDK, types which should not be used for synchronization include:
|
|||||||
* `String` literals
|
* `String` literals
|
||||||
* Primitive wrapper classes in `java.lang` (such as `Boolean` with `Boolean.FALSE` and `Boolean.TRUE`)
|
* Primitive wrapper classes in `java.lang` (such as `Boolean` with `Boolean.FALSE` and `Boolean.TRUE`)
|
||||||
* The class `java.lang.Runtime.Version`
|
* The class `java.lang.Runtime.Version`
|
||||||
* The `Optional*` classes in `java.util`: `Optional`, `OptionalInt`, `OptionalLong`, and `OptionalDouble`
|
* The ``++Optional*++`` classes in `java.util`: `Optional`, `OptionalInt`, `OptionalLong`, and `OptionalDouble`
|
||||||
* Various classes in the `java.time` API: `Instant`, `LocalDate`, `LocalTime`, `LocalDateTime`, `ZonedDateTime`, `ZoneId`, `OffsetTime`, `OffsetDateTime`, `ZoneOffset`, `Duration`, `Period`, `Year`, `YearMonth`, and `MonthDay`
|
* Various classes in the `java.time` API: `Instant`, `LocalDate`, `LocalTime`, `LocalDateTime`, `ZonedDateTime`, `ZoneId`, `OffsetTime`, `OffsetDateTime`, `ZoneOffset`, `Duration`, `Period`, `Year`, `YearMonth`, and `MonthDay`
|
||||||
* Various classes in the `java.time.chrono` API: `MinguoDate`, `HijrahDate`, `JapaneseDate`, and `ThaiBuddhistDate`
|
* Various classes in the `java.time.chrono` API: `MinguoDate`, `HijrahDate`, `JapaneseDate`, and `ThaiBuddhistDate`
|
||||||
* The interface `java.lang.ProcessHandle` and its implementation classes
|
* The interface `java.lang.ProcessHandle` and its implementation classes
|
||||||
|
@ -5,7 +5,7 @@ Both ``++if-else++`` chains and ``++switch++`` statements are used for condition
|
|||||||
* In an ``++if-else++`` chain, each condition is checked in order, and only the block associated with the first true condition is executed. If no condition is true, the code inside the ``++else++`` block (if present) will be executed.
|
* In an ``++if-else++`` chain, each condition is checked in order, and only the block associated with the first true condition is executed. If no condition is true, the code inside the ``++else++`` block (if present) will be executed.
|
||||||
* In a ``++switch++`` statement, the expression is evaluated once, and its value is compared against each case. If a matching case is found, the corresponding block of code is executed. The ``++break++`` statement is used to exit the ``++switch++`` block after a match. If no case matches the expression, the code inside the ``++default++`` block (if present) will be executed.
|
* In a ``++switch++`` statement, the expression is evaluated once, and its value is compared against each case. If a matching case is found, the corresponding block of code is executed. The ``++break++`` statement is used to exit the ``++switch++`` block after a match. If no case matches the expression, the code inside the ``++default++`` block (if present) will be executed.
|
||||||
|
|
||||||
Having the same condition in both ``++if-else++`` chains and `++switch++`` cases can lead to unreachable code and a potential source of bugs. It defeats the purpose of conditional branching and can make the code harder to read and maintain.
|
Having the same condition in both ``++if-else++`` chains and ``++switch++`` cases can lead to unreachable code and a potential source of bugs. It defeats the purpose of conditional branching and can make the code harder to read and maintain.
|
||||||
|
|
||||||
[source,javascript,diff-id=1,diff-type=noncompliant]
|
[source,javascript,diff-id=1,diff-type=noncompliant]
|
||||||
----
|
----
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Casting expressions are utilized to convert one data type to another, such as transforming an integer into a string. This is especially crucial in strongly typed languages like `C`, `C++`, `C#`, `Java`, `Python`, and others.
|
Casting expressions are utilized to convert one data type to another, such as transforming an integer into a string. This is especially crucial in strongly typed languages like C, {cpp}, C#, Java, Python, and others.
|
||||||
|
|
||||||
However, there are instances where casting expressions are not needed. These include situations like:
|
However, there are instances where casting expressions are not needed. These include situations like:
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@ However, the way they perform that task differs, and they should not be used int
|
|||||||
* ``++include++`` also includes a file, but generates only a warning if an error occurs.
|
* ``++include++`` also includes a file, but generates only a warning if an error occurs.
|
||||||
|
|
||||||
Predictably, the difference between ``++require++`` and ``++require_once++`` is the same as the difference between ``++include++`` and ``++include_once++``.
|
Predictably, the difference between ``++require++`` and ``++require_once++`` is the same as the difference between ``++include++`` and ``++include_once++``.
|
||||||
The `_once` versions ensure that the specified file is only included once.
|
The ``++_once++`` versions ensure that the specified file is only included once.
|
||||||
|
|
||||||
=== What is the potential impact?
|
=== What is the potential impact?
|
||||||
|
|
||||||
Including the same file multiple times could have unpredictable results, the `_once` versions are preferred.
|
Including the same file multiple times could have unpredictable results, the ``++_once++`` versions are preferred.
|
||||||
Additionally, as ``++include_once++`` generates only warnings, it should be used only when the file is being included conditionally, i.e. when all possible error conditions have been checked beforehand.
|
Additionally, as ``++include_once++`` generates only warnings, it should be used only when the file is being included conditionally, i.e. when all possible error conditions have been checked beforehand.
|
||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
|
@ -12,10 +12,11 @@ The library helps you to get rid of common dangerous characters, such as:
|
|||||||
* `$`
|
* `$`
|
||||||
* `>`
|
* `>`
|
||||||
* `<`
|
* `<`
|
||||||
* `\``
|
* `++`++`
|
||||||
* `\\`
|
* `++\++`
|
||||||
* `!`
|
* `!`
|
||||||
|
|
||||||
|
|
||||||
If user input is to be included in the arguments of a command, the application
|
If user input is to be included in the arguments of a command, the application
|
||||||
must ensure that dangerous options or argument delimiters are neutralized. +
|
must ensure that dangerous options or argument delimiters are neutralized. +
|
||||||
Argument delimiters count `'`, `-` and spaces.
|
Argument delimiters count `'`, `-` and spaces.
|
||||||
|
@ -10,8 +10,7 @@ The ++arguments++ object has two deprecated properties called ``++arguments.call
|
|||||||
|
|
||||||
Both ``++arguments.caller++`` and ``++arguments.callee++`` are non-standard, deprecated, and leak stack information, which poses security risks and severely limits the possibility of optimizations.
|
Both ``++arguments.caller++`` and ``++arguments.callee++`` are non-standard, deprecated, and leak stack information, which poses security risks and severely limits the possibility of optimizations.
|
||||||
|
|
||||||
Accessing ``arguments.callee``, ``Function.prototype.caller`` and ``Function.prototype.arguments
|
Accessing ``arguments.callee``, ``Function.prototype.caller`` and ``Function.prototype.arguments`` in strict mode will throw a ``TypeError``.
|
||||||
`` in strict mode will throw a ``TypeError``.
|
|
||||||
|
|
||||||
[source,javascript]
|
[source,javascript]
|
||||||
----
|
----
|
||||||
|
@ -58,9 +58,9 @@ ifdef::env-github,rspecator-view[]
|
|||||||
|
|
||||||
=== Message
|
=== Message
|
||||||
|
|
||||||
Remove backticks (`) from "xxx".
|
Remove backticks ``++`++`` from "xxx".
|
||||||
|
|
||||||
Remove backticks (`) from "xxx" and rename it.
|
Remove backticks ``++`++`` from "xxx" and rename it.
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -21,7 +21,7 @@ public async void button1_Click(object sender, EventArgs e)
|
|||||||
await DoSomethingAsync();
|
await DoSomethingAsync();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
* Methods name matching `On[A-Z]\w*` pattern.
|
* Methods name matching ``++On[A-Z]\w*++`` pattern.
|
||||||
+
|
+
|
||||||
Some frameworks may not use the same `EventHandler` method signature
|
Some frameworks may not use the same `EventHandler` method signature
|
||||||
+
|
+
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
For better organization and clarity in test suites, test classes should end with `*Test.php`.
|
For better organization and clarity in test suites, test classes should end with ``++*Test.php++``.
|
||||||
This naming convention helps to easily identify and distinguish test classes from other classes in the codebase.
|
This naming convention helps to easily identify and distinguish test classes from other classes in the codebase.
|
||||||
It allows for automated test runners or frameworks to locate and execute the tests systematically.
|
It allows for automated test runners or frameworks to locate and execute the tests systematically.
|
||||||
|
|
||||||
The PHPUnit command-line test runner will look for `*Test.php` files.
|
The PHPUnit command-line test runner will look for ``++*Test.php++`` files.
|
||||||
In that case, test files without this pattern are ignored and not executed without warning.
|
In that case, test files without this pattern are ignored and not executed without warning.
|
||||||
|
|
||||||
=== What is the potential impact?
|
=== What is the potential impact?
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
The standard PHPUnit assertion methods such as `__assertEquals__`, expect the first argument to be the expected value and the second argument to be the actual value.
|
The standard PHPUnit assertion methods such as ``++__assertEquals__++``, expect the first argument to be the expected value and the second argument to be the actual value.
|
||||||
|
|
||||||
include::../impact.adoc[]
|
include::../impact.adoc[]
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
If a ``++RuntimeException++`` is thrown while code is unit tested, it's likely to be thrown again in production. Therefore, test methods should be allowed to \``++throw RuntimeException++``s so you're alerted early to problems in the code.
|
If a ``++RuntimeException++`` is thrown while code is unit tested, it's likely to be thrown again in production. Therefore, test methods should be allowed to ``++throw RuntimeException++``s so you're alerted early to problems in the code.
|
||||||
|
|
||||||
|
|
||||||
=== Noncompliant code example
|
=== Noncompliant code example
|
||||||
|
@ -53,7 +53,7 @@ and discourage the further use of the application.
|
|||||||
|
|
||||||
=== Exceptions
|
=== Exceptions
|
||||||
|
|
||||||
If a function `+return+`s a pointer to the caller or stores it in an external structure,
|
If a function ``return``s a pointer to the caller or stores it in an external structure,
|
||||||
this pointer is said to _escape_ (it is now accessible outside of function, and no longer local to it).
|
this pointer is said to _escape_ (it is now accessible outside of function, and no longer local to it).
|
||||||
This includes storing the pointer in a static or global variable,
|
This includes storing the pointer in a static or global variable,
|
||||||
passing it to a function that can potentially do that,
|
passing it to a function that can potentially do that,
|
||||||
|
@ -7,7 +7,7 @@ Attempting to release any other type of memory is _undefined behavior_.
|
|||||||
|
|
||||||
The following non-heap memory types may not be released:
|
The following non-heap memory types may not be released:
|
||||||
|
|
||||||
* Stack allocated memory - local variables or memory allocated with the `alloca`, `_alloca`, `_malloca` and `__builtin_alloca` functions.
|
* Stack allocated memory - local variables or memory allocated with the `alloca`, ``++_alloca++``, ``++_malloca++`` and ``++__builtin_alloca++`` functions.
|
||||||
* Executable program code - function pointers.
|
* Executable program code - function pointers.
|
||||||
* Program data - global and static variables.
|
* Program data - global and static variables.
|
||||||
* Read-only program data - constants and strings.
|
* Read-only program data - constants and strings.
|
||||||
|
@ -9,7 +9,7 @@ Proprietary compiler extensions can be handy, but they commit you to always usin
|
|||||||
* Index range in array initializers
|
* Index range in array initializers
|
||||||
* A array initializer without ``++=++``
|
* A array initializer without ``++=++``
|
||||||
* A structure member initializer with a colon
|
* A structure member initializer with a colon
|
||||||
* Decimal floating points numbers `_Decimal32`, `_Decimal64`, and `_Decimal128`
|
* Decimal floating points numbers ``++_Decimal32++``, ``++_Decimal64++``, and ``++_Decimal128++``
|
||||||
* Structures and union without named data members
|
* Structures and union without named data members
|
||||||
|
|
||||||
=== Noncompliant code example
|
=== Noncompliant code example
|
||||||
|
@ -28,7 +28,7 @@ ifdef::env-github,rspecator-view[]
|
|||||||
|
|
||||||
=== Message
|
=== Message
|
||||||
|
|
||||||
Replace the quotes (["|']) with back-ticks (`).
|
Replace the quotes ``++["|']++`` with back-ticks ``++`++``.
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
The way an `#include` directive finds an actual file is implementation-defined, and in practice, it slightly differs in different systems.
|
The way an ``++#include++`` directive finds an actual file is implementation-defined, and in practice, it slightly differs in different systems.
|
||||||
|
|
||||||
Therefore, a good practice is to identify the files to include in the most straightforward way possible to reduce the risk of inconsistent behaviors.
|
Therefore, a good practice is to identify the files to include in the most straightforward way possible to reduce the risk of inconsistent behaviors.
|
||||||
|
|
||||||
This rule raises an issue when:
|
This rule raises an issue when:
|
||||||
|
|
||||||
* The case of the file in the `#include` directive does not match the case of the file on the disk (the inclusion would not work on a case-sensitive OS),
|
* The case of the file in the ``++#include++`` directive does not match the case of the file on the disk (the inclusion would not work on a case-sensitive OS),
|
||||||
* The file name in the `#include` directive contains trailing spaces (they would be ignored on Windows but considered on Unix).
|
* The file name in the ``++#include++`` directive contains trailing spaces (they would be ignored on Windows but considered on Unix).
|
||||||
|
|
||||||
|
|
||||||
=== Noncompliant code example
|
=== Noncompliant code example
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Operator precedence determines the order in which different operators are evaluated when an expression contains multiple ones. It helps determine how the expression is parsed and executed. JavaScript follows a specific set of rules to determine operator precedence.
|
Operator precedence determines the order in which different operators are evaluated when an expression contains multiple ones. It helps determine how the expression is parsed and executed. JavaScript follows a specific set of rules to determine operator precedence.
|
||||||
|
|
||||||
Not being aware of JavaScript's operator precedence rules can lead to unexpected and potentially incorrect results when evaluating expressions. This is common when misapplying the logical negation operator (``++!++``). For instance, consider the difference between ``++!key in dict++`` and ``++!(key in dict)++``. The first looks for a boolean value (``++!key++``) in ``++dict++``, and the other looks for a string and inverts the result. The same applies for ``++!obj instanceof SomeClass++`
|
Not being aware of JavaScript's operator precedence rules can lead to unexpected and potentially incorrect results when evaluating expressions. This is common when misapplying the logical negation operator (``++!++``). For instance, consider the difference between ``++!key in dict++`` and ``++!(key in dict)++``. The first looks for a boolean value (``++!key++``) in ``++dict++``, and the other looks for a string and inverts the result. The same applies for ``++!obj instanceof SomeClass++``.
|
||||||
|
|
||||||
This rule raises an issue when the left operand of an ``++in++`` or ``++instanceof++`` operator is negated with ``++!++``.
|
This rule raises an issue when the left operand of an ``++in++`` or ``++instanceof++`` operator is negated with ``++!++``.
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
Pointer and unmanaged function pointer types such as `IntPtr`, `UIntPtr`, `int*` etc. are used to access unmanaged memory, usually in order to use C or {cpp} libraries. If such a pointer is not secured by making it `private`, `internal` or `readonly`, it can lead to a vulnerability allowing access to arbitrary locations.
|
Pointer and unmanaged function pointer types such as `IntPtr`, `UIntPtr`, ``++int*++`` etc. are used to access unmanaged memory, usually in order to use C or {cpp} libraries. If such a pointer is not secured by making it `private`, `internal` or `readonly`, it can lead to a vulnerability allowing access to arbitrary locations.
|
||||||
|
|
||||||
|
|
||||||
=== Noncompliant code example
|
=== Noncompliant code example
|
||||||
|
@ -8,7 +8,7 @@ This rule raises an issue in the following cases:
|
|||||||
** does not return any value
|
** does not return any value
|
||||||
** does not access the field with the corresponding name (if it exists).
|
** does not access the field with the corresponding name (if it exists).
|
||||||
|
|
||||||
Underscore prefixes for fields are supported, so `setX()` can assign a value to `_x`.
|
Underscore prefixes for fields are supported, so `setX()` can assign a value to ``++_x++``.
|
||||||
|
|
||||||
The following type of getters and setters are supported:
|
The following type of getters and setters are supported:
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ In all cases, the attack surface of an affected application is increased. In som
|
|||||||
== Ask Yourself Whether
|
== Ask Yourself Whether
|
||||||
|
|
||||||
* The development of the app is completed and the development feature is activated.
|
* The development of the app is completed and the development feature is activated.
|
||||||
* The app is distributed to end users with the `development feature activated
|
* The app is distributed to end users with the development feature activated
|
||||||
|
|
||||||
There is a risk if you answered yes to any of those questions.
|
There is a risk if you answered yes to any of those questions.
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
include::../../common/fix/code-rationale.adoc[]
|
include::../../common/fix/code-rationale.adoc[]
|
||||||
|
|
||||||
Certificate validation is not enabled by default when `_create_unverified_context`
|
Certificate validation is not enabled by default when ``++_create_unverified_context++``
|
||||||
is used. It is recommended to use `_create_default_https_context` instead to
|
is used. It is recommended to use ``++_create_default_https_context++`` instead to
|
||||||
create a secure context that validates certificates.
|
create a secure context that validates certificates.
|
||||||
|
|
||||||
==== Noncompliant code example
|
==== Noncompliant code example
|
||||||
|
@ -194,7 +194,7 @@ When applicable, it is recommended to replace the VLA with heap-allocated memory
|
|||||||
In contrast to VLA, heap allocation functions report in a situation when sufficient memory cannot be provided, by returning `NULL` or throwing an exception (in {cpp}).
|
In contrast to VLA, heap allocation functions report in a situation when sufficient memory cannot be provided, by returning `NULL` or throwing an exception (in {cpp}).
|
||||||
Furthermore, the {cpp} standard library provides containers like `std::vector`, that manage the heap-allocated memory.
|
Furthermore, the {cpp} standard library provides containers like `std::vector`, that manage the heap-allocated memory.
|
||||||
|
|
||||||
Moreover, the C11 language standard and above only optionally supports VLAs (with `__STDC_NO_VLA__`),
|
Moreover, the C11 language standard and above only optionally supports VLAs (with ``++__STDC_NO_VLA__++``),
|
||||||
and the {cpp} standard never supported it, however, they are commonly accepted as extensions.
|
and the {cpp} standard never supported it, however, they are commonly accepted as extensions.
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm[There is a limit] to the number of batch jobs which can be executed at the same time. Executing batch jobs in triggers or in loops is complex as it can easily reach this limit (example: after a bulk update), thus it is recommended to avoid it. Note that checking if the limit is already reached is not enough as nothing prevents the addition of a job between the check and the subsequent call to ``++executeBatch++``.
|
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm[There is a limit] to the number of batch jobs which can be executed at the same time. Executing batch jobs in triggers or in loops is complex as it can easily reach this limit (example: after a bulk update), thus it is recommended to avoid it. Note that checking if the limit is already reached is not enough as nothing prevents the addition of a job between the check and the subsequent call to ``++executeBatch++``.
|
||||||
|
|
||||||
|
|
||||||
This rule raises an issue when \``++Databasee.executeBatch()++`` is called in a Trigger or in a loop.
|
This rule raises an issue when ``++Databasee.executeBatch()++`` is called in a Trigger or in a loop.
|
||||||
|
|
||||||
|
|
||||||
=== Noncompliant code example
|
=== Noncompliant code example
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
Salesforce Governor Limits do not allow more than 10 calls to \``++Messaging.sendEmail++`` in a single transaction. There is a good chance that calling this method in a loop will reach that limit and fail. You can instead send a batch of emails with a single call to \``++Messaging.sendEmail++``.
|
Salesforce Governor Limits do not allow more than 10 calls to ``++Messaging.sendEmail++`` in a single transaction. There is a good chance that calling this method in a loop will reach that limit and fail. You can instead send a batch of emails with a single call to ``++Messaging.sendEmail++``.
|
||||||
|
|
||||||
|
|
||||||
This rule raises an issue when a call to ``++Messaging.sendEmail++`` is found in a loop.
|
This rule raises an issue when a call to ``++Messaging.sendEmail++`` is found in a loop.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
include::../../common/fix/code-rationale.adoc[]
|
include::../../common/fix/code-rationale.adoc[]
|
||||||
|
|
||||||
Certificate validation is not enabled by default when
|
Certificate validation is not enabled by default when
|
||||||
`_create_unverified_context` or `_create_stdlib_context` is used. It is
|
``++_create_unverified_context++`` or ``++_create_stdlib_context++`` is used. It is
|
||||||
recommended to use `create_default_context`, without explicitly setting
|
recommended to use `create_default_context`, without explicitly setting
|
||||||
`check_hostname` to `False`. +
|
`check_hostname` to `False`. +
|
||||||
Doing so creates a secure context that validates both hostnames and
|
Doing so creates a secure context that validates both hostnames and
|
||||||
|
@ -21,11 +21,12 @@ with MyContextManager():
|
|||||||
----
|
----
|
||||||
|
|
||||||
will output:
|
will output:
|
||||||
```
|
[source,text]
|
||||||
|
----
|
||||||
Entering
|
Entering
|
||||||
Executing body
|
Executing body
|
||||||
Exiting
|
Exiting
|
||||||
```
|
----
|
||||||
|
|
||||||
If either the ``++__enter__++`` or the ``++__exit__++`` method is missing, an ``AttributeError`` will be raised instead.
|
If either the ``++__enter__++`` or the ``++__exit__++`` method is missing, an ``AttributeError`` will be raised instead.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
The function `size_t strlen(const char *s)` measures the length of the string `s` (excluding the final null character). +
|
The function ``++size_t strlen(const char *s)++`` measures the length of the string `s` (excluding the final null character). +
|
||||||
The function `size_t wcslen(const wchar_t *s)` does the same for wide characters, and should be used with the same guidelines.
|
The function ``++size_t wcslen(const wchar_t *s)++`` does the same for wide characters, and should be used with the same guidelines.
|
||||||
|
|
||||||
Similarly to many other functions in the standard C libraries,
|
Similarly to many other functions in the standard C libraries,
|
||||||
`strlen` and `wcslen` assume that their argument is not a null pointer.
|
`strlen` and `wcslen` assume that their argument is not a null pointer.
|
||||||
|
@ -29,7 +29,7 @@ Note: This scenario can only happen before {cpp}17. Since {cpp}17, the standard
|
|||||||
Using `make_unique()` doesn't impact performance, but `make_shared()` improves it slightly. +
|
Using `make_unique()` doesn't impact performance, but `make_shared()` improves it slightly. +
|
||||||
Indeed, constructing explicitly a `shared_ptr()` requires two heap allocations: one for the managed object and the other for the control block that stores data about the ref-counts and the `shared_ptr()` deleter. `make_shared()` on the other hand, performs only one heap allocation.
|
Indeed, constructing explicitly a `shared_ptr()` requires two heap allocations: one for the managed object and the other for the control block that stores data about the ref-counts and the `shared_ptr()` deleter. `make_shared()` on the other hand, performs only one heap allocation.
|
||||||
|
|
||||||
Note: Because `make_shared` performs only one allocation for both the object and the control block, the memory occupied by the object will be deallocated when no `shared_ptr` or `weak_ptr` points to it. If the object is large, a `weak_ptr` is used, and memory is a concern, explicitly calling the constructor of `shared_ptr` may be preferred. This way, the object's memory will be deallocated when there are no more shared owners, independently of any `weak_ptr`s.
|
Note: Because `make_shared` performs only one allocation for both the object and the control block, the memory occupied by the object will be deallocated when no `shared_ptr` or `weak_ptr` points to it. If the object is large, a `weak_ptr` is used, and memory is a concern, explicitly calling the constructor of `shared_ptr` may be preferred. This way, the object's memory will be deallocated when there are no more shared owners, independently of any ``weak_ptr``s.
|
||||||
|
|
||||||
=== Noncompliant code example
|
=== Noncompliant code example
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ void g() {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
In this case ``++str++`` will not be converted to a ``++std::string++`` when calling the function ``++find++``, and each element of the bucket that corresponds to the hash of ``++str++`` will be compared using homogeneous ``++operator==++``,
|
In this case ``++str++`` will not be converted to a ``++std::string++`` when calling the function ``++find++``, and each element of the bucket that corresponds to the hash of ``++str++`` will be compared using homogeneous ``++operator==++``,
|
||||||
and for each such comparison, a conversion will now happen. The number of compared elements varies depending on the hash distribution from ``++O(1)++` (on average) to ``++O(N)++`` (in the worst case).
|
and for each such comparison, a conversion will now happen. The number of compared elements varies depending on the hash distribution from ``++O(1)++`` (on average) to ``++O(N)++`` (in the worst case).
|
||||||
As consequence, the performance of slow runs (when multiple hash collisions happen due to the data distribution) is made even worse.
|
As consequence, the performance of slow runs (when multiple hash collisions happen due to the data distribution) is made even worse.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Compare integers of mixed signedness safely using `std::cmp_*` functions to avoid any unexpected results.
|
Compare integers of mixed signedness safely using ``++std::cmp_*++`` functions to avoid any unexpected results.
|
||||||
|
|
||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ For example, using container size functions in a comparison can lead to such a p
|
|||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
|
|
||||||
{cpp}20 introduced a remedy to this common pitfall: a family of `std::cmp_*` functions defined in the `<utility>` header.
|
{cpp}20 introduced a remedy to this common pitfall: a family of ``++std::cmp_*++`` functions defined in the `<utility>` header.
|
||||||
These functions correctly handle negative numbers and lossy integer conversion.
|
These functions correctly handle negative numbers and lossy integer conversion.
|
||||||
For example, `std::cmp_less(2U, -1)` is `false`.
|
For example, `std::cmp_less(2U, -1)` is `false`.
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ In {cpp}20 ``++std::to_address++`` was introduced to perform this operation on b
|
|||||||
* The first option was to take the address of the element pointed by the iterator: ``++&*it++``. However, this operation has undefined behavior if the iterator is not pointing to any element. This may happen for the iterator returned by a call to ``++end()++`` on the container. This may also be the case when we need the address to construct a new object (via placement new) at the location pointed to by the iterator. ``++std::to_address(it)++`` works in such cases.
|
* The first option was to take the address of the element pointed by the iterator: ``++&*it++``. However, this operation has undefined behavior if the iterator is not pointing to any element. This may happen for the iterator returned by a call to ``++end()++`` on the container. This may also be the case when we need the address to construct a new object (via placement new) at the location pointed to by the iterator. ``++std::to_address(it)++`` works in such cases.
|
||||||
* The second option was to exploit the nature of ``++operator->++`` overloading and call it explicitly on the iterator: ``++it.operator->()++``. This option avoids the pitfalls of the previous one, at the cost of not being portable. It would fail on the implementations that use raw-pointers as iterators for contiguous ranges like ``++std::vector++`` or ``++std::span++``. Moreover, it is confusing, as this functional notation syntax for operators is rarely used.
|
* The second option was to exploit the nature of ``++operator->++`` overloading and call it explicitly on the iterator: ``++it.operator->()++``. This option avoids the pitfalls of the previous one, at the cost of not being portable. It would fail on the implementations that use raw-pointers as iterators for contiguous ranges like ``++std::vector++`` or ``++std::span++``. Moreover, it is confusing, as this functional notation syntax for operators is rarely used.
|
||||||
|
|
||||||
While both ``++std::to_address++` and above workarounds, can be always used to get the address of the element that the iterator is pointing to (if any), incrementing or decrementing may have undefined behavior.
|
While both ``++std::to_address++`` and above workarounds, can be always used to get the address of the element that the iterator is pointing to (if any), incrementing or decrementing may have undefined behavior.
|
||||||
Performing pointer arithmetic on pointer to elements is safe only in the case of contiguous iterators (e.g. iterators of `std::vector`, `std::array`, `std::span`, `std::string` or `std::string_view`).
|
Performing pointer arithmetic on pointer to elements is safe only in the case of contiguous iterators (e.g. iterators of `std::vector`, `std::array`, `std::span`, `std::string` or `std::string_view`).
|
||||||
|
|
||||||
This rule raises an issue when dereferencing a pointer-like object is immediately followed by taking the address of the result (``++&*x++`` or ``++std::addressof(*x)++``) or when ``++operator->++`` is called through an explicit functional notation (``++x.operator->()++``).
|
This rule raises an issue when dereferencing a pointer-like object is immediately followed by taking the address of the result (``++&*x++`` or ``++std::addressof(*x)++``) or when ``++operator->++`` is called through an explicit functional notation (``++x.operator->()++``).
|
||||||
|
@ -51,7 +51,7 @@ https://cloud.google.com/iam/docs/keys-create-delete#creating[GCP docs].
|
|||||||
==== Compliant solution
|
==== Compliant solution
|
||||||
|
|
||||||
Always avoid committing service account key files to public systems. Use any
|
Always avoid committing service account key files to public systems. Use any
|
||||||
`*ignore` file possible, such as `.gitignore`, `.dockerignore` and equivalents
|
``++*ignore++`` file possible, such as `.gitignore`, `.dockerignore` and equivalents
|
||||||
for any other system accessing your local codebase.
|
for any other system accessing your local codebase.
|
||||||
|
|
||||||
//=== How does this work?
|
//=== How does this work?
|
||||||
|
@ -12,6 +12,6 @@ For example, to match a two-digit number, one could write `+[0-9]{2,2}+` or `+\d
|
|||||||
This rule recommends replacing some quantifiers and character classes with more concise equivalents:
|
This rule recommends replacing some quantifiers and character classes with more concise equivalents:
|
||||||
|
|
||||||
* `+\d+` for `+[0-9]+` and `+\D+` for `[^0-9]`
|
* `+\d+` for `+[0-9]+` and `+\D+` for `[^0-9]`
|
||||||
* `+\w+` for `+[A-Za-z0-9_]+` and `+\W+` for `[^A-Za-z0-9_]`
|
* `+\w+` for `+[A-Za-z0-9_]+` and `+\W+` for ``++[^A-Za-z0-9_]++``
|
||||||
* `+.+` for character classes matching everything (e.g. `+[\w\W]+`, `+[\d\D]+`, or `+[\s\S]+` with `+s+` flag)
|
* `+.+` for character classes matching everything (e.g. `+[\w\W]+`, `+[\d\D]+`, or `+[\s\S]+` with `+s+` flag)
|
||||||
* `+x?+` for `+x{0,1}+`, `+x*+` for `+x{0,}+`, `+x++` for `+x{1,}+`, `+x{N}+` for `+x{N,N}+`
|
* `+x?+` for `+x{0,1}+`, `+x*+` for `+x{0,}+`, `+x++` for `+x{1,}+`, `+x{N}+` for `+x{N,N}+`
|
@ -162,6 +162,6 @@ include::../message.adoc[]
|
|||||||
=== Highlighting
|
=== Highlighting
|
||||||
|
|
||||||
* For ``Microsoft.Batch/batchAccounts/pools``, highlight ``"elevationLevel": "Admin"``.
|
* For ``Microsoft.Batch/batchAccounts/pools``, highlight ``"elevationLevel": "Admin"``.
|
||||||
* For ``Microsoft.ContainerRegistry/registries``, highlight `"adminUserEnabled": true``.
|
* For ``Microsoft.ContainerRegistry/registries``, highlight ``"adminUserEnabled": true``.
|
||||||
|
|
||||||
endif::env-github,rspecator-view[]
|
endif::env-github,rspecator-view[]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
The class `std::optional<T>` either stores a value of type `T` or is empty.
|
The class `std::optional<T>` either stores a value of type `T` or is empty.
|
||||||
|
|
||||||
One way to access the value of a non-empty optional is the `operator*`. But using the dereference operator gives the optional appearance of a pointer when it is not: it models an object. Additionally, attempting to call the `operator*` on an empty optional will result in undefined behavior.
|
One way to access the value of a non-empty optional is the ``++operator*++``. But using the dereference operator gives the optional appearance of a pointer when it is not: it models an object. Additionally, attempting to call the ``++operator*++`` on an empty optional will result in undefined behavior.
|
||||||
|
|
||||||
Another way to access the value of a non-empty optional is the function `value()`. But assigning a value to the optional object through this function will throw an exception (`std::bad_optional_access`) if the optional has no value, and the assignment will not happen.
|
Another way to access the value of a non-empty optional is the function `value()`. But assigning a value to the optional object through this function will throw an exception (`std::bad_optional_access`) if the optional has no value, and the assignment will not happen.
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ For the assignment of an optional to happen correctly, whatever its state, it is
|
|||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
|
|
||||||
The rule raises an issue when the `operator*` or the `value()` function are used to assign a new value to an optional.
|
The rule raises an issue when the ``++operator*++`` or the `value()` function are used to assign a new value to an optional.
|
||||||
|
|
||||||
=== Code examples
|
=== Code examples
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ Make sure it is safe to use host operating system namespaces here.
|
|||||||
|
|
||||||
=== Highlighting
|
=== Highlighting
|
||||||
|
|
||||||
Highlight `host___: true`.
|
Highlight ``++host___: true++``.
|
||||||
|
|
||||||
endif::env-github,rspecator-view[]
|
endif::env-github,rspecator-view[]
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
Catching `ExceptionGroup` with `except*` will raise a `TypeError`.
|
Catching `ExceptionGroup` with ``++except*++`` will raise a `TypeError`.
|
||||||
|
|
||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
Python 3.11 introduced `except*` and `ExceptionGroup`, making it possible to handle and raise multiple unrelated exceptions simultaneously.
|
Python 3.11 introduced ``++except*++`` and `ExceptionGroup`, making it possible to handle and raise multiple unrelated exceptions simultaneously.
|
||||||
|
|
||||||
In the example below, we gather multiple exceptions in an `ExceptionGroup`. This `ExceptionGroup` is then caught by a single except block:
|
In the example below, we gather multiple exceptions in an `ExceptionGroup`. This `ExceptionGroup` is then caught by a single except block:
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ except ExceptionGroup as exceptions:
|
|||||||
pass
|
pass
|
||||||
----
|
----
|
||||||
|
|
||||||
To handle differently each type of exceptions present in an `ExceptionGroup`, we have to use the `except*` keyword.
|
To handle differently each type of exceptions present in an `ExceptionGroup`, we have to use the ``++except*++`` keyword.
|
||||||
|
|
||||||
[source,python]
|
[source,python]
|
||||||
----
|
----
|
||||||
@ -36,7 +36,7 @@ except* TypeError as t:
|
|||||||
pass
|
pass
|
||||||
----
|
----
|
||||||
|
|
||||||
While it is possible to catch the `ExceptionGroup` and `BaseExceptionGroup` types with `except`, a `TypeError` will be raised when this is done with `except*`.
|
While it is possible to catch the `ExceptionGroup` and `BaseExceptionGroup` types with `except`, a `TypeError` will be raised when this is done with ``++except*++``.
|
||||||
|
|
||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
|
@ -11,7 +11,7 @@ The values are stored using 64 bits in the following form:
|
|||||||
// When images can be added, add image based on to this one
|
// When images can be added, add image based on to this one
|
||||||
//image::IEEE_754_Double_Floating_Point_Format.svg.png[]
|
//image::IEEE_754_Double_Floating_Point_Format.svg.png[]
|
||||||
|
|
||||||
The actual value of the stored number will be `(-1)^sign^ * (1 + significand) * 2 ^exponent^`
|
The actual value of the stored number will be `pass:n[(-1)^sign^ * (1 + significand) * 2 ^exponent^]`
|
||||||
|
|
||||||
Given this structure, there are limits in both *magnitude* and *precision*.
|
Given this structure, there are limits in both *magnitude* and *precision*.
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ myBigInt + 1n === myBigInt + 2n; // false
|
|||||||
|
|
||||||
For large numbers, JavaScript provides the helper function `Number.isSafeInteger()` to test if a number is between the safe limits.
|
For large numbers, JavaScript provides the helper function `Number.isSafeInteger()` to test if a number is between the safe limits.
|
||||||
|
|
||||||
When you need to store a large number, use `BigInt`. `bigint` and `number` primitives can be compared between them as usual (e.g. `>`, `==`), but pay attention that arithmetic operations (`+` `pass:[*]` `-` `%` `pass:[**]`) between both types raise an error unless they are converted to the same type. Use the `BigInt` and `Number` functions to convert between both types:
|
When you need to store a large number, use `BigInt`. `bigint` and `number` primitives can be compared between them as usual (e.g. `>`, `==`), but pay attention that arithmetic operations (`+` `pass:[*]` `-` `%` `++**++`) between both types raise an error unless they are converted to the same type. Use the `BigInt` and `Number` functions to convert between both types:
|
||||||
[source,javascript]
|
[source,javascript]
|
||||||
----
|
----
|
||||||
const myNumber = Number(myBigInt);
|
const myNumber = Number(myBigInt);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
This rule ensures that Django models have a `__str__` method defined.
|
This rule ensures that Django models have a ``++__str__++`` method defined.
|
||||||
|
|
||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
The `__str__` method in Django models is used to represent the model instance as a string. For example, the return value of this method will be inserted in a template when displaying an object in the Django admin site. Without this method, the model instance will be represented by its object identifier, which is not meaningful to end-users. This can result in confusion and make debugging more difficult.
|
The ``++__str__++`` method in Django models is used to represent the model instance as a string. For example, the return value of this method will be inserted in a template when displaying an object in the Django admin site. Without this method, the model instance will be represented by its object identifier, which is not meaningful to end-users. This can result in confusion and make debugging more difficult.
|
||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
|
|
||||||
To fix this issue, the Django model must define a `__str__` method that returns a string representation of the instance. This string should be meaningful to end-users and provide information about the model instance.
|
To fix this issue, the Django model must define a ``++__str__++`` method that returns a string representation of the instance. This string should be meaningful to end-users and provide information about the model instance.
|
||||||
|
|
||||||
=== Code examples
|
=== Code examples
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
This rule discourages the use of `exclude` or `__all__` with ModelForm in Django and suggests using fields instead.
|
This rule discourages the use of `exclude` or ``++__all__++`` with ModelForm in Django and suggests using fields instead.
|
||||||
|
|
||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
In Django, when creating a `ModelForm`, it is common to use `exclude` to remove fields from the form. It is also possible to set the `fields` value to `__all__` to conveniently indicate that all the model fields should be included in the form. However, this can lead to security issues when new fields are added to the model, as they will automatically be included in the form, which may not be intended. Additionally, `exclude` or `__all__` can make it harder to maintain the codebase by hiding the dependencies between the model and the form.
|
In Django, when creating a `ModelForm`, it is common to use `exclude` to remove fields from the form. It is also possible to set the `fields` value to ``++__all__++`` to conveniently indicate that all the model fields should be included in the form. However, this can lead to security issues when new fields are added to the model, as they will automatically be included in the form, which may not be intended. Additionally, `exclude` or ``++__all__++`` can make it harder to maintain the codebase by hiding the dependencies between the model and the form.
|
||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
Developers should use the "fields" attribute instead of "exclude" or "all" when creating ModelForms in Django. This ensures that all fields are explicitly listed and makes it clear what fields are included in the form.
|
Developers should use the "fields" attribute instead of "exclude" or "all" when creating ModelForms in Django. This ensures that all fields are explicitly listed and makes it clear what fields are included in the form.
|
||||||
|
@ -35,7 +35,7 @@ This code will print `"Hello World"`, omitting the leading and trailing whitespa
|
|||||||
|
|
||||||
==== Compliant solution
|
==== Compliant solution
|
||||||
|
|
||||||
This example demonstrates pathname expansion using the `echo` command, which will print `"command t*.sh"` as intended:
|
This example demonstrates pathname expansion using the `echo` command, which will print ``++"command t*.sh"++`` as intended:
|
||||||
[source,docker,diff-id=1,diff-type=compliant]
|
[source,docker,diff-id=1,diff-type=compliant]
|
||||||
----
|
----
|
||||||
RUN test="command t*.sh" && echo "$test"
|
RUN test="command t*.sh" && echo "$test"
|
||||||
|
@ -57,10 +57,11 @@ public void EndsWith_Char()
|
|||||||
|
|
||||||
Hardware configuration:
|
Hardware configuration:
|
||||||
|
|
||||||
```
|
[source,text]
|
||||||
|
----
|
||||||
BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2846/22H2/2022Update)
|
BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2846/22H2/2022Update)
|
||||||
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
|
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
|
||||||
.NET SDK=7.0.203
|
.NET SDK=7.0.203
|
||||||
[Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
[Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
||||||
.NET 7.0 : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
.NET 7.0 : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
||||||
```
|
----
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
JavaScript has a prototypical inheritance model. Each object has an internal property that points to another object, called a `prototype`. That prototype object has a prototype of its own, and the whole sequence is called a *prototype chain*. When accessing a property or a method of an object, if it is not found at the top level, the search continues through the object's prototype and then further down the prototype chain. This feature allows for very powerful dynamic inheritance patterns but can also lead to confusion when compared to the classic inheritance.
|
JavaScript has a prototypical inheritance model. Each object has an internal property that points to another object, called a `prototype`. That prototype object has a prototype of its own, and the whole sequence is called a *prototype chain*. When accessing a property or a method of an object, if it is not found at the top level, the search continues through the object's prototype and then further down the prototype chain. This feature allows for very powerful dynamic inheritance patterns but can also lead to confusion when compared to the classic inheritance.
|
||||||
|
|
||||||
To simplify the access to the prototype of an object some browsers introduced the `\\__proto__` property, which was later deprecated and removed from the language. The current ECMAScript standard includes `Object.getPrototype` and `Object.setPrototype` static methods that should be used instead of the `\\__proto__` property.
|
To simplify the access to the prototype of an object some browsers introduced the ``++__proto__++`` property, which was later deprecated and removed from the language. The current ECMAScript standard includes `Object.getPrototype` and `Object.setPrototype` static methods that should be used instead of the ``++__proto__++`` property.
|
||||||
|
|
||||||
[source,javascript,diff-id=1,diff-type=noncompliant]
|
[source,javascript,diff-id=1,diff-type=noncompliant]
|
||||||
----
|
----
|
||||||
@ -10,7 +10,7 @@ let prototype = foo.__proto__; // Noncompliant: use Object.getPrototype
|
|||||||
foo.__proto__ = bar; // Noncompliant: use Object.setPrototype
|
foo.__proto__ = bar; // Noncompliant: use Object.setPrototype
|
||||||
----
|
----
|
||||||
|
|
||||||
To fix your code replace `\\__proto__` with calls to `Object.getPrototype` and `Object.setPrototype` static methods.
|
To fix your code replace ``++__proto__++`` with calls to `Object.getPrototype` and `Object.setPrototype` static methods.
|
||||||
|
|
||||||
[source,javascript,diff-id=1,diff-type=compliant]
|
[source,javascript,diff-id=1,diff-type=compliant]
|
||||||
----
|
----
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user