mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 20:10:09 +00:00
parent
4ddcdd02d6
commit
cecd4b166c
4 changed files with 150 additions and 138 deletions
|
@ -632,7 +632,7 @@ For more, see [pydocstyle](https://pypi.org/project/pydocstyle/6.1.1/) on PyPI.
|
||||||
| D202 | NoBlankLineAfterFunction | No blank lines allowed after function docstring (found 1) | 🛠 |
|
| D202 | NoBlankLineAfterFunction | No blank lines allowed after function docstring (found 1) | 🛠 |
|
||||||
| D203 | OneBlankLineBeforeClass | 1 blank line required before class docstring | 🛠 |
|
| D203 | OneBlankLineBeforeClass | 1 blank line required before class docstring | 🛠 |
|
||||||
| D204 | OneBlankLineAfterClass | 1 blank line required after class docstring | 🛠 |
|
| D204 | OneBlankLineAfterClass | 1 blank line required after class docstring | 🛠 |
|
||||||
| D205 | BlankLineAfterSummary | 1 blank line required between summary line and description | 🛠 |
|
| D205 | BlankLineAfterSummary | 1 blank line required between summary line and description (found 2) | 🛠 |
|
||||||
| D206 | IndentWithSpaces | Docstring should be indented with spaces, not tabs | |
|
| D206 | IndentWithSpaces | Docstring should be indented with spaces, not tabs | |
|
||||||
| D207 | NoUnderIndentation | Docstring is under-indented | 🛠 |
|
| D207 | NoUnderIndentation | Docstring is under-indented | 🛠 |
|
||||||
| D208 | NoOverIndentation | Docstring is over-indented | 🛠 |
|
| D208 | NoOverIndentation | Docstring is over-indented | 🛠 |
|
||||||
|
|
|
@ -336,21 +336,21 @@ pub fn blank_after_summary(checker: &mut Checker, docstring: &Docstring) {
|
||||||
}
|
}
|
||||||
if lines_count > 1 && blanks_count != 1 {
|
if lines_count > 1 && blanks_count != 1 {
|
||||||
let mut check = Check::new(
|
let mut check = Check::new(
|
||||||
CheckKind::BlankLineAfterSummary,
|
CheckKind::BlankLineAfterSummary(blanks_count),
|
||||||
Range::from_located(docstring.expr),
|
Range::from_located(docstring.expr),
|
||||||
);
|
);
|
||||||
if checker.patch(check.kind.code()) {
|
if checker.patch(check.kind.code()) {
|
||||||
// Find the "summary" line (defined as the first non-blank line).
|
|
||||||
let mut summary_line = 0;
|
|
||||||
for line in body.lines() {
|
|
||||||
if line.trim().is_empty() {
|
|
||||||
summary_line += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if blanks_count > 1 {
|
if blanks_count > 1 {
|
||||||
|
// Find the "summary" line (defined as the first non-blank line).
|
||||||
|
let mut summary_line = 0;
|
||||||
|
for line in body.lines() {
|
||||||
|
if line.trim().is_empty() {
|
||||||
|
summary_line += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Insert one blank line after the summary (replacing any existing lines).
|
// Insert one blank line after the summary (replacing any existing lines).
|
||||||
check.amend(Fix::replacement(
|
check.amend(Fix::replacement(
|
||||||
"\n".to_string(),
|
"\n".to_string(),
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
source: src/pydocstyle/mod.rs
|
source: src/pydocstyle/mod.rs
|
||||||
expression: checks
|
expression: checks
|
||||||
---
|
---
|
||||||
- kind: BlankLineAfterSummary
|
- kind:
|
||||||
|
BlankLineAfterSummary: 0
|
||||||
location:
|
location:
|
||||||
row: 200
|
row: 200
|
||||||
column: 4
|
column: 4
|
||||||
|
@ -11,7 +12,8 @@ expression: checks
|
||||||
column: 7
|
column: 7
|
||||||
fix: ~
|
fix: ~
|
||||||
parent: ~
|
parent: ~
|
||||||
- kind: BlankLineAfterSummary
|
- kind:
|
||||||
|
BlankLineAfterSummary: 2
|
||||||
location:
|
location:
|
||||||
row: 210
|
row: 210
|
||||||
column: 4
|
column: 4
|
||||||
|
|
258
src/registry.rs
258
src/registry.rs
|
@ -1005,7 +1005,7 @@ pub enum CheckKind {
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
BlankLineAfterLastSection(String),
|
BlankLineAfterLastSection(String),
|
||||||
BlankLineAfterSection(String),
|
BlankLineAfterSection(String),
|
||||||
BlankLineAfterSummary,
|
BlankLineAfterSummary(usize),
|
||||||
BlankLineBeforeSection(String),
|
BlankLineBeforeSection(String),
|
||||||
CapitalizeSectionName(String),
|
CapitalizeSectionName(String),
|
||||||
DashedUnderlineAfterSection(String),
|
DashedUnderlineAfterSection(String),
|
||||||
|
@ -1465,7 +1465,7 @@ impl CheckCode {
|
||||||
CheckCode::D202 => CheckKind::NoBlankLineAfterFunction(1),
|
CheckCode::D202 => CheckKind::NoBlankLineAfterFunction(1),
|
||||||
CheckCode::D203 => CheckKind::OneBlankLineBeforeClass(0),
|
CheckCode::D203 => CheckKind::OneBlankLineBeforeClass(0),
|
||||||
CheckCode::D204 => CheckKind::OneBlankLineAfterClass(0),
|
CheckCode::D204 => CheckKind::OneBlankLineAfterClass(0),
|
||||||
CheckCode::D205 => CheckKind::BlankLineAfterSummary,
|
CheckCode::D205 => CheckKind::BlankLineAfterSummary(2),
|
||||||
CheckCode::D206 => CheckKind::IndentWithSpaces,
|
CheckCode::D206 => CheckKind::IndentWithSpaces,
|
||||||
CheckCode::D207 => CheckKind::NoUnderIndentation,
|
CheckCode::D207 => CheckKind::NoUnderIndentation,
|
||||||
CheckCode::D208 => CheckKind::NoOverIndentation,
|
CheckCode::D208 => CheckKind::NoOverIndentation,
|
||||||
|
@ -2268,7 +2268,7 @@ impl CheckKind {
|
||||||
CheckKind::NewLineAfterLastParagraph => &CheckCode::D209,
|
CheckKind::NewLineAfterLastParagraph => &CheckCode::D209,
|
||||||
CheckKind::NewLineAfterSectionName(..) => &CheckCode::D406,
|
CheckKind::NewLineAfterSectionName(..) => &CheckCode::D406,
|
||||||
CheckKind::NoBlankLineAfterFunction(..) => &CheckCode::D202,
|
CheckKind::NoBlankLineAfterFunction(..) => &CheckCode::D202,
|
||||||
CheckKind::BlankLineAfterSummary => &CheckCode::D205,
|
CheckKind::BlankLineAfterSummary(..) => &CheckCode::D205,
|
||||||
CheckKind::NoBlankLineBeforeClass(..) => &CheckCode::D211,
|
CheckKind::NoBlankLineBeforeClass(..) => &CheckCode::D211,
|
||||||
CheckKind::NoBlankLineBeforeFunction(..) => &CheckCode::D201,
|
CheckKind::NoBlankLineBeforeFunction(..) => &CheckCode::D201,
|
||||||
CheckKind::NoBlankLinesBetweenHeaderAndContent(..) => &CheckCode::D412,
|
CheckKind::NoBlankLinesBetweenHeaderAndContent(..) => &CheckCode::D412,
|
||||||
|
@ -3093,8 +3093,15 @@ impl CheckKind {
|
||||||
}
|
}
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(),
|
CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(),
|
||||||
CheckKind::BlankLineAfterSummary => {
|
CheckKind::BlankLineAfterSummary(num_lines) => {
|
||||||
"1 blank line required between summary line and description".to_string()
|
if *num_lines == 0 {
|
||||||
|
"1 blank line required between summary line and description".to_string()
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"1 blank line required between summary line and description (found \
|
||||||
|
{num_lines})"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CheckKind::NewLineAfterLastParagraph => {
|
CheckKind::NewLineAfterLastParagraph => {
|
||||||
"Multi-line docstring closing quotes should be on a separate line".to_string()
|
"Multi-line docstring closing quotes should be on a separate line".to_string()
|
||||||
|
@ -3624,125 +3631,128 @@ impl CheckKind {
|
||||||
|
|
||||||
/// Whether the check kind is (potentially) fixable.
|
/// Whether the check kind is (potentially) fixable.
|
||||||
pub fn fixable(&self) -> bool {
|
pub fn fixable(&self) -> bool {
|
||||||
matches!(
|
match self {
|
||||||
self,
|
// Always-fixable checks.
|
||||||
CheckKind::AAndNotA(..)
|
CheckKind::AAndNotA(..)
|
||||||
| CheckKind::AOrNotA(..)
|
| CheckKind::AOrNotA(..)
|
||||||
| CheckKind::AmbiguousUnicodeCharacterComment(..)
|
| CheckKind::AmbiguousUnicodeCharacterComment(..)
|
||||||
| CheckKind::AmbiguousUnicodeCharacterDocstring(..)
|
| CheckKind::AmbiguousUnicodeCharacterDocstring(..)
|
||||||
| CheckKind::AmbiguousUnicodeCharacterString(..)
|
| CheckKind::AmbiguousUnicodeCharacterString(..)
|
||||||
| CheckKind::AndFalse
|
| CheckKind::AndFalse
|
||||||
| CheckKind::BlankLineAfterLastSection(..)
|
| CheckKind::BlankLineAfterLastSection(..)
|
||||||
| CheckKind::BlankLineAfterSection(..)
|
| CheckKind::BlankLineAfterSection(..)
|
||||||
| CheckKind::BlankLineAfterSummary
|
| CheckKind::BlankLineBeforeSection(..)
|
||||||
| CheckKind::BlankLineBeforeSection(..)
|
| CheckKind::CapitalizeSectionName(..)
|
||||||
| CheckKind::CapitalizeSectionName(..)
|
| CheckKind::CommentedOutCode
|
||||||
| CheckKind::CommentedOutCode
|
| CheckKind::ConvertLoopToAll(..)
|
||||||
| CheckKind::ConvertLoopToAll(..)
|
| CheckKind::ConvertLoopToAny(..)
|
||||||
| CheckKind::ConvertLoopToAny(..)
|
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
|
||||||
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
|
| CheckKind::ConvertTypedDictFunctionalToClass(..)
|
||||||
| CheckKind::ConvertTypedDictFunctionalToClass(..)
|
| CheckKind::DashedUnderlineAfterSection(..)
|
||||||
| CheckKind::DashedUnderlineAfterSection(..)
|
| CheckKind::DatetimeTimezoneUTC
|
||||||
| CheckKind::DatetimeTimezoneUTC
|
| CheckKind::DeprecatedUnittestAlias(..)
|
||||||
| CheckKind::DeprecatedUnittestAlias(..)
|
| CheckKind::DoNotAssertFalse
|
||||||
| CheckKind::DoNotAssertFalse
|
| CheckKind::DoNotAssignLambda(..)
|
||||||
| CheckKind::DoNotAssignLambda(..)
|
| CheckKind::DupeClassFieldDefinitions(..)
|
||||||
| CheckKind::DupeClassFieldDefinitions(..)
|
| CheckKind::DuplicateHandlerException(..)
|
||||||
| CheckKind::DuplicateHandlerException(..)
|
| CheckKind::DuplicateIsinstanceCall(..)
|
||||||
| CheckKind::DuplicateIsinstanceCall(..)
|
| CheckKind::EndsInPeriod
|
||||||
| CheckKind::EndsInPeriod
|
| CheckKind::EndsInPunctuation
|
||||||
| CheckKind::EndsInPunctuation
|
| CheckKind::FStringMissingPlaceholders
|
||||||
| CheckKind::FStringMissingPlaceholders
|
| CheckKind::GetAttrWithConstant
|
||||||
| CheckKind::GetAttrWithConstant
|
| CheckKind::ImplicitReturn
|
||||||
| CheckKind::ImplicitReturn
|
| CheckKind::ImplicitReturnValue
|
||||||
| CheckKind::ImplicitReturnValue
|
| CheckKind::IncorrectFixtureParenthesesStyle(..)
|
||||||
| CheckKind::IncorrectFixtureParenthesesStyle(..)
|
| CheckKind::IncorrectMarkParenthesesStyle(..)
|
||||||
| CheckKind::IncorrectMarkParenthesesStyle(..)
|
| CheckKind::InvalidEscapeSequence(..)
|
||||||
| CheckKind::InvalidEscapeSequence(..)
|
| CheckKind::IsLiteral(..)
|
||||||
| CheckKind::IsLiteral(..)
|
| CheckKind::KeyInDict(..)
|
||||||
| CheckKind::KeyInDict(..)
|
| CheckKind::MisplacedComparisonConstant(..)
|
||||||
| CheckKind::MisplacedComparisonConstant(..)
|
| CheckKind::MissingReturnTypeSpecialMethod(..)
|
||||||
| CheckKind::MissingReturnTypeSpecialMethod(..)
|
| CheckKind::NativeLiterals(..)
|
||||||
| CheckKind::NativeLiterals(..)
|
| CheckKind::NewLineAfterLastParagraph
|
||||||
| CheckKind::NewLineAfterLastParagraph
|
| CheckKind::NewLineAfterSectionName(..)
|
||||||
| CheckKind::NewLineAfterSectionName(..)
|
| CheckKind::NoBlankLineAfterFunction(..)
|
||||||
| CheckKind::NoBlankLineAfterFunction(..)
|
| CheckKind::NoBlankLineBeforeClass(..)
|
||||||
| CheckKind::NoBlankLineBeforeClass(..)
|
| CheckKind::NoBlankLineBeforeFunction(..)
|
||||||
| CheckKind::NoBlankLineBeforeFunction(..)
|
| CheckKind::NoBlankLinesBetweenHeaderAndContent(..)
|
||||||
| CheckKind::NoBlankLinesBetweenHeaderAndContent(..)
|
| CheckKind::NoNewLineAtEndOfFile
|
||||||
| CheckKind::NoNewLineAtEndOfFile
|
| CheckKind::NoOverIndentation
|
||||||
| CheckKind::NoOverIndentation
|
| CheckKind::NoSurroundingWhitespace
|
||||||
| CheckKind::NoSurroundingWhitespace
|
| CheckKind::NoUnderIndentation
|
||||||
| CheckKind::NoUnderIndentation
|
| CheckKind::NoUnnecessaryPass
|
||||||
| CheckKind::NoUnnecessaryPass
|
| CheckKind::NoneComparison(..)
|
||||||
| CheckKind::NoneComparison(..)
|
| CheckKind::NotInTest
|
||||||
| CheckKind::NotInTest
|
| CheckKind::NotIsTest
|
||||||
| CheckKind::NotIsTest
|
| CheckKind::OSErrorAlias(..)
|
||||||
| CheckKind::OSErrorAlias(..)
|
| CheckKind::OneBlankLineAfterClass(..)
|
||||||
| CheckKind::OneBlankLineAfterClass(..)
|
| CheckKind::OneBlankLineBeforeClass(..)
|
||||||
| CheckKind::OneBlankLineBeforeClass(..)
|
| CheckKind::OpenAlias
|
||||||
| CheckKind::OpenAlias
|
| CheckKind::OrTrue
|
||||||
| CheckKind::OrTrue
|
| CheckKind::PEP3120UnnecessaryCodingComment
|
||||||
| CheckKind::PEP3120UnnecessaryCodingComment
|
| CheckKind::PPrintFound
|
||||||
| CheckKind::PPrintFound
|
| CheckKind::ParametrizeNamesWrongType(..)
|
||||||
| CheckKind::ParametrizeNamesWrongType(..)
|
| CheckKind::PercentFormatExtraNamedArguments(..)
|
||||||
| CheckKind::PercentFormatExtraNamedArguments(..)
|
| CheckKind::PreferListBuiltin
|
||||||
| CheckKind::PreferListBuiltin
|
| CheckKind::PrintFound
|
||||||
| CheckKind::PrintFound
|
| CheckKind::RaiseNotImplemented
|
||||||
| CheckKind::RaiseNotImplemented
|
| CheckKind::RedundantOpenModes(..)
|
||||||
| CheckKind::RedundantOpenModes(..)
|
| CheckKind::RedundantTupleInExceptionHandler(..)
|
||||||
| CheckKind::RedundantTupleInExceptionHandler(..)
|
| CheckKind::RemoveSixCompat
|
||||||
| CheckKind::RemoveSixCompat
|
| CheckKind::ReplaceStdoutStderr
|
||||||
| CheckKind::ReplaceStdoutStderr
|
| CheckKind::ReplaceUniversalNewlines
|
||||||
| CheckKind::ReplaceUniversalNewlines
|
| CheckKind::RewriteCElementTree
|
||||||
| CheckKind::RewriteCElementTree
|
| CheckKind::RewriteListComprehension
|
||||||
| CheckKind::RewriteListComprehension
|
| CheckKind::RewriteMockImport(..)
|
||||||
| CheckKind::RewriteMockImport(..)
|
| CheckKind::RewriteUnicodeLiteral
|
||||||
| CheckKind::RewriteUnicodeLiteral
|
| CheckKind::RewriteYieldFrom
|
||||||
| CheckKind::RewriteYieldFrom
|
| CheckKind::SectionNameEndsInColon(..)
|
||||||
| CheckKind::SectionNameEndsInColon(..)
|
| CheckKind::SectionNotOverIndented(..)
|
||||||
| CheckKind::SectionNotOverIndented(..)
|
| CheckKind::SectionUnderlineAfterName(..)
|
||||||
| CheckKind::SectionUnderlineAfterName(..)
|
| CheckKind::SectionUnderlineMatchesSectionLength(..)
|
||||||
| CheckKind::SectionUnderlineMatchesSectionLength(..)
|
| CheckKind::SectionUnderlineNotOverIndented(..)
|
||||||
| CheckKind::SectionUnderlineNotOverIndented(..)
|
| CheckKind::SetAttrWithConstant
|
||||||
| CheckKind::SetAttrWithConstant
|
| CheckKind::StringDotFormatExtraNamedArguments(..)
|
||||||
| CheckKind::StringDotFormatExtraNamedArguments(..)
|
| CheckKind::SuperCallWithParameters
|
||||||
| CheckKind::SuperCallWithParameters
|
| CheckKind::TrueFalseComparison(..)
|
||||||
| CheckKind::TrueFalseComparison(..)
|
| CheckKind::TypeOfPrimitive(..)
|
||||||
| CheckKind::TypeOfPrimitive(..)
|
| CheckKind::TypingTextStrAlias
|
||||||
| CheckKind::TypingTextStrAlias
|
| CheckKind::UnnecessaryBuiltinImport(..)
|
||||||
| CheckKind::UnnecessaryBuiltinImport(..)
|
| CheckKind::UnnecessaryCallAroundSorted(..)
|
||||||
| CheckKind::UnnecessaryCallAroundSorted(..)
|
| CheckKind::UnnecessaryCollectionCall(..)
|
||||||
| CheckKind::UnnecessaryCollectionCall(..)
|
| CheckKind::UnnecessaryComprehension(..)
|
||||||
| CheckKind::UnnecessaryComprehension(..)
|
| CheckKind::UnnecessaryEncodeUTF8
|
||||||
| CheckKind::UnnecessaryEncodeUTF8
|
| CheckKind::UnnecessaryFutureImport(..)
|
||||||
| CheckKind::UnnecessaryFutureImport(..)
|
| CheckKind::UnnecessaryGeneratorDict
|
||||||
| CheckKind::UnnecessaryGeneratorDict
|
| CheckKind::UnnecessaryGeneratorList
|
||||||
| CheckKind::UnnecessaryGeneratorList
|
| CheckKind::UnnecessaryGeneratorSet
|
||||||
| CheckKind::UnnecessaryGeneratorSet
|
| CheckKind::UnnecessaryLRUCacheParams
|
||||||
| CheckKind::UnnecessaryLRUCacheParams
|
| CheckKind::UnnecessaryListCall
|
||||||
| CheckKind::UnnecessaryListCall
|
| CheckKind::UnnecessaryListComprehensionDict
|
||||||
| CheckKind::UnnecessaryListComprehensionDict
|
| CheckKind::UnnecessaryListComprehensionSet
|
||||||
| CheckKind::UnnecessaryListComprehensionSet
|
| CheckKind::UnnecessaryLiteralDict(..)
|
||||||
| CheckKind::UnnecessaryLiteralDict(..)
|
| CheckKind::UnnecessaryLiteralSet(..)
|
||||||
| CheckKind::UnnecessaryLiteralSet(..)
|
| CheckKind::UnnecessaryLiteralWithinListCall(..)
|
||||||
| CheckKind::UnnecessaryLiteralWithinListCall(..)
|
| CheckKind::UnnecessaryLiteralWithinTupleCall(..)
|
||||||
| CheckKind::UnnecessaryLiteralWithinTupleCall(..)
|
| CheckKind::UnnecessaryReturnNone
|
||||||
| CheckKind::UnnecessaryReturnNone
|
| CheckKind::UnsortedImports
|
||||||
| CheckKind::UnsortedImports
|
| CheckKind::UnusedLoopControlVariable(..)
|
||||||
| CheckKind::UnusedImport(_, false, _)
|
| CheckKind::UnusedNOQA(..)
|
||||||
| CheckKind::UnusedLoopControlVariable(..)
|
| CheckKind::UseFixturesWithoutParameters
|
||||||
| CheckKind::UnusedNOQA(..)
|
| CheckKind::UsePEP585Annotation(..)
|
||||||
| CheckKind::UseFixturesWithoutParameters
|
| CheckKind::UsePEP604Annotation
|
||||||
| CheckKind::UsePEP585Annotation(..)
|
| CheckKind::UseSysExit(..)
|
||||||
| CheckKind::UsePEP604Annotation
|
| CheckKind::UselessImportAlias
|
||||||
| CheckKind::UseSysExit(..)
|
| CheckKind::UselessMetaclassType
|
||||||
| CheckKind::UselessImportAlias
|
| CheckKind::UselessObjectInheritance(..)
|
||||||
| CheckKind::UselessMetaclassType
|
| CheckKind::UselessYieldFixture(..)
|
||||||
| CheckKind::UselessObjectInheritance(..)
|
| CheckKind::YodaConditions(..) => true,
|
||||||
| CheckKind::UselessYieldFixture(..)
|
// Conditionally-fixable checks.
|
||||||
| CheckKind::YodaConditions(..)
|
CheckKind::UnusedImport(_, false, _) => true,
|
||||||
)
|
CheckKind::BlankLineAfterSummary(num_lines) if *num_lines > 0 => true,
|
||||||
|
// Non-fixable checks.
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message used to describe the fix action for a given `CheckKind`.
|
/// The message used to describe the fix action for a given `CheckKind`.
|
||||||
|
@ -3762,7 +3772,7 @@ impl CheckKind {
|
||||||
CheckKind::BlankLineAfterSection(name) => {
|
CheckKind::BlankLineAfterSection(name) => {
|
||||||
Some(format!("Add blank line after \"{name}\""))
|
Some(format!("Add blank line after \"{name}\""))
|
||||||
}
|
}
|
||||||
CheckKind::BlankLineAfterSummary => Some("Insert single blank line".to_string()),
|
CheckKind::BlankLineAfterSummary(..) => Some("Insert single blank line".to_string()),
|
||||||
CheckKind::BlankLineBeforeSection(name) => {
|
CheckKind::BlankLineBeforeSection(name) => {
|
||||||
Some(format!("Add blank line before \"{name}\""))
|
Some(format!("Add blank line before \"{name}\""))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue