mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(linter/jsdoc): implement no-blank-blocks rule (#25207)
this PR implements `jsdoc/no-blank-blocks` rule, issue #1170
This commit is contained in:
1 parent
648a4814ea
commit
ccb8fe89db
8 files changed
+405
-1
No files matched your search
@@ -1035,6 +1035,7 @@ export interface DummyRuleMap {
|
||||
"jsdoc/check-tag-names"?: RuleNoConfig | [AllowWarnDeny, CheckTagNamesConfig];
|
||||
"jsdoc/empty-tags"?: RuleNoConfig | [AllowWarnDeny, EmptyTagsConfig];
|
||||
"jsdoc/implements-on-classes"?: RuleNoConfig;
|
||||
"jsdoc/no-blank-blocks"?: RuleNoConfig | [AllowWarnDeny, NoBlankBlocks];
|
||||
"jsdoc/no-defaults"?: RuleNoConfig | [AllowWarnDeny, NoDefaultsConfig];
|
||||
"jsdoc/require-param"?: RuleNoConfig | [AllowWarnDeny, RequireParamConfig];
|
||||
"jsdoc/require-param-description"?: RuleNoConfig | [AllowWarnDeny, RequireParamDescriptionConfig];
|
||||
@@ -2575,6 +2576,12 @@ export interface EmptyTagsConfig {
|
||||
*/
|
||||
tags?: string[];
|
||||
}
|
||||
export interface NoBlankBlocks {
|
||||
/**
|
||||
* Whether to automatically remove blank JSDoc blocks.
|
||||
*/
|
||||
enableFixer?: boolean;
|
||||
}
|
||||
export interface NoDefaultsConfig {
|
||||
/**
|
||||
* If true, report the presence of optional param names (square brackets) on `@param` tags.
|
||||
|
||||
@@ -4463,6 +4463,11 @@ impl RuleRunner for crate::rules::jsdoc::implements_on_classes::ImplementsOnClas
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::jsdoc::no_blank_blocks::NoBlankBlocks {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> = None;
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::RunOnce;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::jsdoc::no_defaults::NoDefaults {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> =
|
||||
Some(&AstTypesBitset::from_types(&[AstType::ArrowFunctionExpression, AstType::Function]));
|
||||
|
||||
+27
-1
@@ -295,6 +295,7 @@ pub use crate::rules::jsdoc::check_property_names::CheckPropertyNames as JsdocCh
|
||||
pub use crate::rules::jsdoc::check_tag_names::CheckTagNames as JsdocCheckTagNames;
|
||||
pub use crate::rules::jsdoc::empty_tags::EmptyTags as JsdocEmptyTags;
|
||||
pub use crate::rules::jsdoc::implements_on_classes::ImplementsOnClasses as JsdocImplementsOnClasses;
|
||||
pub use crate::rules::jsdoc::no_blank_blocks::NoBlankBlocks as JsdocNoBlankBlocks;
|
||||
pub use crate::rules::jsdoc::no_defaults::NoDefaults as JsdocNoDefaults;
|
||||
pub use crate::rules::jsdoc::require_param::RequireParam as JsdocRequireParam;
|
||||
pub use crate::rules::jsdoc::require_param_description::RequireParamDescription as JsdocRequireParamDescription;
|
||||
@@ -1559,6 +1560,7 @@ pub enum RuleEnum {
|
||||
JsdocCheckTagNames(JsdocCheckTagNames),
|
||||
JsdocEmptyTags(JsdocEmptyTags),
|
||||
JsdocImplementsOnClasses(JsdocImplementsOnClasses),
|
||||
JsdocNoBlankBlocks(JsdocNoBlankBlocks),
|
||||
JsdocNoDefaults(JsdocNoDefaults),
|
||||
JsdocRequireParam(JsdocRequireParam),
|
||||
JsdocRequireParamDescription(JsdocRequireParamDescription),
|
||||
@@ -2503,7 +2505,8 @@ const JSDOC_CHECK_PROPERTY_NAMES_ID: usize = JSDOC_CHECK_ACCESS_ID + 1usize;
|
||||
const JSDOC_CHECK_TAG_NAMES_ID: usize = JSDOC_CHECK_PROPERTY_NAMES_ID + 1usize;
|
||||
const JSDOC_EMPTY_TAGS_ID: usize = JSDOC_CHECK_TAG_NAMES_ID + 1usize;
|
||||
const JSDOC_IMPLEMENTS_ON_CLASSES_ID: usize = JSDOC_EMPTY_TAGS_ID + 1usize;
|
||||
const JSDOC_NO_DEFAULTS_ID: usize = JSDOC_IMPLEMENTS_ON_CLASSES_ID + 1usize;
|
||||
const JSDOC_NO_BLANK_BLOCKS_ID: usize = JSDOC_IMPLEMENTS_ON_CLASSES_ID + 1usize;
|
||||
const JSDOC_NO_DEFAULTS_ID: usize = JSDOC_NO_BLANK_BLOCKS_ID + 1usize;
|
||||
const JSDOC_REQUIRE_PARAM_ID: usize = JSDOC_NO_DEFAULTS_ID + 1usize;
|
||||
const JSDOC_REQUIRE_PARAM_DESCRIPTION_ID: usize = JSDOC_REQUIRE_PARAM_ID + 1usize;
|
||||
const JSDOC_REQUIRE_PARAM_NAME_ID: usize = JSDOC_REQUIRE_PARAM_DESCRIPTION_ID + 1usize;
|
||||
@@ -3488,6 +3491,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JSDOC_CHECK_TAG_NAMES_ID,
|
||||
Self::JsdocEmptyTags(_) => JSDOC_EMPTY_TAGS_ID,
|
||||
Self::JsdocImplementsOnClasses(_) => JSDOC_IMPLEMENTS_ON_CLASSES_ID,
|
||||
Self::JsdocNoBlankBlocks(_) => JSDOC_NO_BLANK_BLOCKS_ID,
|
||||
Self::JsdocNoDefaults(_) => JSDOC_NO_DEFAULTS_ID,
|
||||
Self::JsdocRequireParam(_) => JSDOC_REQUIRE_PARAM_ID,
|
||||
Self::JsdocRequireParamDescription(_) => JSDOC_REQUIRE_PARAM_DESCRIPTION_ID,
|
||||
@@ -4458,6 +4462,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::NAME,
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::NAME,
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::NAME,
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::NAME,
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::NAME,
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::NAME,
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::NAME,
|
||||
@@ -5468,6 +5473,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::CATEGORY,
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::CATEGORY,
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::CATEGORY,
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::CATEGORY,
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::CATEGORY,
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::CATEGORY,
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::CATEGORY,
|
||||
@@ -6449,6 +6455,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::FIX,
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::FIX,
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::FIX,
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::FIX,
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::FIX,
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::FIX,
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::FIX,
|
||||
@@ -7628,6 +7635,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::documentation(),
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::documentation(),
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::documentation(),
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::documentation(),
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::documentation(),
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::documentation(),
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::documentation(),
|
||||
@@ -9843,6 +9851,8 @@ impl RuleEnum {
|
||||
.or_else(|| JsdocEmptyTags::schema(generator)),
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::config_schema(generator)
|
||||
.or_else(|| JsdocImplementsOnClasses::schema(generator)),
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::config_schema(generator)
|
||||
.or_else(|| JsdocNoBlankBlocks::schema(generator)),
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::config_schema(generator)
|
||||
.or_else(|| JsdocNoDefaults::schema(generator)),
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::config_schema(generator)
|
||||
@@ -10986,6 +10996,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => "jsdoc",
|
||||
Self::JsdocEmptyTags(_) => "jsdoc",
|
||||
Self::JsdocImplementsOnClasses(_) => "jsdoc",
|
||||
Self::JsdocNoBlankBlocks(_) => "jsdoc",
|
||||
Self::JsdocNoDefaults(_) => "jsdoc",
|
||||
Self::JsdocRequireParam(_) => "jsdoc",
|
||||
Self::JsdocRequireParamDescription(_) => "jsdoc",
|
||||
@@ -13371,6 +13382,9 @@ impl RuleEnum {
|
||||
Self::JsdocImplementsOnClasses(_) => Ok(Self::JsdocImplementsOnClasses(
|
||||
JsdocImplementsOnClasses::from_configuration(value)?,
|
||||
)),
|
||||
Self::JsdocNoBlankBlocks(_) => {
|
||||
Ok(Self::JsdocNoBlankBlocks(JsdocNoBlankBlocks::from_configuration(value)?))
|
||||
}
|
||||
Self::JsdocNoDefaults(_) => {
|
||||
Ok(Self::JsdocNoDefaults(JsdocNoDefaults::from_configuration(value)?))
|
||||
}
|
||||
@@ -14577,6 +14591,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(rule) => rule.to_configuration(),
|
||||
Self::JsdocEmptyTags(rule) => rule.to_configuration(),
|
||||
Self::JsdocImplementsOnClasses(rule) => rule.to_configuration(),
|
||||
Self::JsdocNoBlankBlocks(rule) => rule.to_configuration(),
|
||||
Self::JsdocNoDefaults(rule) => rule.to_configuration(),
|
||||
Self::JsdocRequireParam(rule) => rule.to_configuration(),
|
||||
Self::JsdocRequireParamDescription(rule) => rule.to_configuration(),
|
||||
@@ -15432,6 +15447,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(rule) => rule.run(node, ctx),
|
||||
Self::JsdocEmptyTags(rule) => rule.run(node, ctx),
|
||||
Self::JsdocImplementsOnClasses(rule) => rule.run(node, ctx),
|
||||
Self::JsdocNoBlankBlocks(rule) => rule.run(node, ctx),
|
||||
Self::JsdocNoDefaults(rule) => rule.run(node, ctx),
|
||||
Self::JsdocRequireParam(rule) => rule.run(node, ctx),
|
||||
Self::JsdocRequireParamDescription(rule) => rule.run(node, ctx),
|
||||
@@ -16297,6 +16313,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(rule) => rule.run_once(ctx),
|
||||
Self::JsdocEmptyTags(rule) => rule.run_once(ctx),
|
||||
Self::JsdocImplementsOnClasses(rule) => rule.run_once(ctx),
|
||||
Self::JsdocNoBlankBlocks(rule) => rule.run_once(ctx),
|
||||
Self::JsdocNoDefaults(rule) => rule.run_once(ctx),
|
||||
Self::JsdocRequireParam(rule) => rule.run_once(ctx),
|
||||
Self::JsdocRequireParamDescription(rule) => rule.run_once(ctx),
|
||||
@@ -17271,6 +17288,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::JsdocEmptyTags(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::JsdocImplementsOnClasses(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::JsdocNoBlankBlocks(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::JsdocNoDefaults(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::JsdocRequireParam(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::JsdocRequireParamDescription(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
@@ -18145,6 +18163,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(rule) => rule.should_run(ctx),
|
||||
Self::JsdocEmptyTags(rule) => rule.should_run(ctx),
|
||||
Self::JsdocImplementsOnClasses(rule) => rule.should_run(ctx),
|
||||
Self::JsdocNoBlankBlocks(rule) => rule.should_run(ctx),
|
||||
Self::JsdocNoDefaults(rule) => rule.should_run(ctx),
|
||||
Self::JsdocRequireParam(rule) => rule.should_run(ctx),
|
||||
Self::JsdocRequireParamDescription(rule) => rule.should_run(ctx),
|
||||
@@ -19315,6 +19334,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::IS_TSGOLINT_RULE,
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::IS_TSGOLINT_RULE,
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::IS_TSGOLINT_RULE,
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::IS_TSGOLINT_RULE,
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::IS_TSGOLINT_RULE,
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::IS_TSGOLINT_RULE,
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::IS_TSGOLINT_RULE,
|
||||
@@ -20383,6 +20403,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::VERSION,
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::VERSION,
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::VERSION,
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::VERSION,
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::VERSION,
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::VERSION,
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::VERSION,
|
||||
@@ -21440,6 +21461,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::HAS_CONFIG,
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::HAS_CONFIG,
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::HAS_CONFIG,
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::HAS_CONFIG,
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::HAS_CONFIG,
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::HAS_CONFIG,
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::HAS_CONFIG,
|
||||
@@ -22430,6 +22452,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(_) => JsdocCheckTagNames::INFO,
|
||||
Self::JsdocEmptyTags(_) => JsdocEmptyTags::INFO,
|
||||
Self::JsdocImplementsOnClasses(_) => JsdocImplementsOnClasses::INFO,
|
||||
Self::JsdocNoBlankBlocks(_) => JsdocNoBlankBlocks::INFO,
|
||||
Self::JsdocNoDefaults(_) => JsdocNoDefaults::INFO,
|
||||
Self::JsdocRequireParam(_) => JsdocRequireParam::INFO,
|
||||
Self::JsdocRequireParamDescription(_) => JsdocRequireParamDescription::INFO,
|
||||
@@ -23295,6 +23318,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(rule) => rule.types_info(),
|
||||
Self::JsdocEmptyTags(rule) => rule.types_info(),
|
||||
Self::JsdocImplementsOnClasses(rule) => rule.types_info(),
|
||||
Self::JsdocNoBlankBlocks(rule) => rule.types_info(),
|
||||
Self::JsdocNoDefaults(rule) => rule.types_info(),
|
||||
Self::JsdocRequireParam(rule) => rule.types_info(),
|
||||
Self::JsdocRequireParamDescription(rule) => rule.types_info(),
|
||||
@@ -24147,6 +24171,7 @@ impl RuleEnum {
|
||||
Self::JsdocCheckTagNames(rule) => rule.run_info(),
|
||||
Self::JsdocEmptyTags(rule) => rule.run_info(),
|
||||
Self::JsdocImplementsOnClasses(rule) => rule.run_info(),
|
||||
Self::JsdocNoBlankBlocks(rule) => rule.run_info(),
|
||||
Self::JsdocNoDefaults(rule) => rule.run_info(),
|
||||
Self::JsdocRequireParam(rule) => rule.run_info(),
|
||||
Self::JsdocRequireParamDescription(rule) => rule.run_info(),
|
||||
@@ -25127,6 +25152,7 @@ pub static RULES: std::sync::LazyLock<Vec<RuleEnum>> = std::sync::LazyLock::new(
|
||||
RuleEnum::JsdocCheckTagNames(JsdocCheckTagNames::default()),
|
||||
RuleEnum::JsdocEmptyTags(JsdocEmptyTags::default()),
|
||||
RuleEnum::JsdocImplementsOnClasses(JsdocImplementsOnClasses::default()),
|
||||
RuleEnum::JsdocNoBlankBlocks(JsdocNoBlankBlocks::default()),
|
||||
RuleEnum::JsdocNoDefaults(JsdocNoDefaults::default()),
|
||||
RuleEnum::JsdocRequireParam(JsdocRequireParam::default()),
|
||||
RuleEnum::JsdocRequireParamDescription(JsdocRequireParamDescription::default()),
|
||||
|
||||
@@ -729,6 +729,7 @@ pub(crate) mod jsdoc {
|
||||
pub mod check_tag_names;
|
||||
pub mod empty_tags;
|
||||
pub mod implements_on_classes;
|
||||
pub mod no_blank_blocks;
|
||||
pub mod no_defaults;
|
||||
pub mod require_param;
|
||||
pub mod require_param_description;
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
rule::{DefaultRuleConfig, Rule},
|
||||
};
|
||||
|
||||
fn no_blank_blocks_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("No empty blocks").with_label(span)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
|
||||
pub struct NoBlankBlocks {
|
||||
/// Whether to automatically remove blank JSDoc blocks.
|
||||
enable_fixer: bool,
|
||||
}
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Reports and optionally removes blocks with whitespace only.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Blank JSDoc blocks add noise without providing any documentation.
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// Examples of **incorrect** code for this rule:
|
||||
/// ```js
|
||||
/// /** */
|
||||
///
|
||||
/// /**
|
||||
/// *
|
||||
/// */
|
||||
/// ```
|
||||
///
|
||||
/// Examples of **correct** code for this rule:
|
||||
/// ```js
|
||||
/// /** @tag */
|
||||
///
|
||||
/// /**
|
||||
/// * Text
|
||||
/// */
|
||||
///
|
||||
/// /**
|
||||
/// * @tag
|
||||
/// */
|
||||
/// ```
|
||||
NoBlankBlocks,
|
||||
jsdoc,
|
||||
style,
|
||||
conditional_fix,
|
||||
config = NoBlankBlocks,
|
||||
version = "next",
|
||||
short_description = "Reports and optionally removes blocks with whitespace only.",
|
||||
);
|
||||
|
||||
impl Rule for NoBlankBlocks {
|
||||
fn from_configuration(value: serde_json::Value) -> Result<Self, serde_json::error::Error> {
|
||||
serde_json::from_value::<DefaultRuleConfig<Self>>(value).map(DefaultRuleConfig::into_inner)
|
||||
}
|
||||
|
||||
fn run_once(&self, ctx: &LintContext) {
|
||||
let source_text = ctx.source_text();
|
||||
|
||||
for jsdoc in ctx.jsdoc().iter_all() {
|
||||
let content = &source_text[jsdoc.span.start as usize..jsdoc.span.end as usize];
|
||||
if !is_blank_jsdoc(content) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let diagnostic = no_blank_blocks_diagnostic(jsdoc.span);
|
||||
if self.enable_fixer
|
||||
&& let Some(span) = fix_span(jsdoc.span, source_text)
|
||||
{
|
||||
ctx.diagnostic_with_fix(diagnostic, |fixer| fixer.delete_range(span));
|
||||
} else {
|
||||
ctx.diagnostic(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the contents between `/**` and `*/` contain only whitespace and JSDoc line delimiters
|
||||
fn is_blank_jsdoc(content: &str) -> bool {
|
||||
content.split('\n').enumerate().all(|(index, line)| {
|
||||
let line = line.trim();
|
||||
line.is_empty() || (index > 0 && line == "*")
|
||||
})
|
||||
}
|
||||
|
||||
/// Expands a standalone JSDoc block to include its indentation and following line ending.
|
||||
fn fix_span(jsdoc_span: Span, source_text: &str) -> Option<Span> {
|
||||
let comment_span = Span::new(jsdoc_span.start - 3, jsdoc_span.end + 2);
|
||||
let prefix = &source_text[..comment_span.start as usize];
|
||||
let line_start = prefix.rfind('\n').map_or(0, |index| index + 1);
|
||||
|
||||
if !prefix[line_start..].bytes().all(|byte| matches!(byte, b' ' | b'\t')) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let suffix = &source_text[comment_span.end as usize..];
|
||||
let line_end = suffix.find(['\r', '\n']).unwrap_or(suffix.len());
|
||||
if !suffix[..line_end].bytes().all(|byte| matches!(byte, b' ' | b'\t')) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let line_ending_len = if suffix[line_end..].starts_with("\r\n") {
|
||||
2
|
||||
} else {
|
||||
usize::from(line_end < suffix.len())
|
||||
};
|
||||
|
||||
Some(Span::new(
|
||||
u32::try_from(line_start).unwrap_or(comment_span.start),
|
||||
comment_span.end + u32::try_from(line_end + line_ending_len).unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
(
|
||||
"
|
||||
/** @tag */
|
||||
",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
* Text
|
||||
*/
|
||||
",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
* @tag
|
||||
*/
|
||||
",
|
||||
None,
|
||||
),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
(
|
||||
"
|
||||
/** */
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*/
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*
|
||||
*/
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": false, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
",
|
||||
None,
|
||||
),
|
||||
("foo();\r\n/** */\r\nbar();", Some(serde_json::json!([ { "enableFixer": true, }, ]))),
|
||||
];
|
||||
|
||||
let fix = vec![
|
||||
(
|
||||
"
|
||||
/** */
|
||||
",
|
||||
"
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*/
|
||||
",
|
||||
"
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*
|
||||
*/
|
||||
",
|
||||
"
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
",
|
||||
"
|
||||
",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"foo();\r\n/** */\r\nbar();",
|
||||
"foo();\r\nbar();",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
(
|
||||
"const result = typeof/** */value;",
|
||||
"const result = typeof/** */value;",
|
||||
Some(serde_json::json!([ { "enableFixer": true, }, ])),
|
||||
),
|
||||
];
|
||||
|
||||
Tester::new(NoBlankBlocks::NAME, NoBlankBlocks::PLUGIN, pass, fail)
|
||||
.expect_fix(fix)
|
||||
.test_and_snapshot();
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
---
|
||||
|
||||
⚠ jsdoc(no-blank-blocks): No empty blocks
|
||||
╭─[no_blank_blocks.tsx:2:24]
|
||||
1 │
|
||||
2 │ /** */
|
||||
· ─
|
||||
3 │
|
||||
╰────
|
||||
help: Delete this code.
|
||||
|
||||
⚠ jsdoc(no-blank-blocks): No empty blocks
|
||||
╭─[no_blank_blocks.tsx:2:24]
|
||||
1 │
|
||||
2 │ ╭─▶ /**
|
||||
3 │ ╰─▶ */
|
||||
4 │
|
||||
╰────
|
||||
help: Delete this code.
|
||||
|
||||
⚠ jsdoc(no-blank-blocks): No empty blocks
|
||||
╭─[no_blank_blocks.tsx:2:24]
|
||||
1 │
|
||||
2 │ ╭─▶ /**
|
||||
3 │ │ *
|
||||
4 │ ╰─▶ */
|
||||
5 │
|
||||
╰────
|
||||
help: Delete this code.
|
||||
|
||||
⚠ jsdoc(no-blank-blocks): No empty blocks
|
||||
╭─[no_blank_blocks.tsx:2:24]
|
||||
1 │
|
||||
2 │ ╭─▶ /**
|
||||
3 │ │ *
|
||||
4 │ │ *
|
||||
5 │ ╰─▶ */
|
||||
6 │
|
||||
╰────
|
||||
help: Delete this code.
|
||||
|
||||
⚠ jsdoc(no-blank-blocks): No empty blocks
|
||||
╭─[no_blank_blocks.tsx:2:24]
|
||||
1 │
|
||||
2 │ ╭─▶ /**
|
||||
3 │ │ *
|
||||
4 │ │ *
|
||||
5 │ ╰─▶ */
|
||||
6 │
|
||||
╰────
|
||||
|
||||
⚠ jsdoc(no-blank-blocks): No empty blocks
|
||||
╭─[no_blank_blocks.tsx:2:24]
|
||||
1 │
|
||||
2 │ ╭─▶ /**
|
||||
3 │ │ *
|
||||
4 │ │ *
|
||||
5 │ ╰─▶ */
|
||||
6 │
|
||||
╰────
|
||||
|
||||
⚠ jsdoc(no-blank-blocks): No empty blocks
|
||||
╭─[no_blank_blocks.tsx:2:4]
|
||||
1 │ foo();
|
||||
2 │ /** */
|
||||
· ─
|
||||
3 │ bar();
|
||||
╰────
|
||||
help: Delete this code.
|
||||
@@ -3581,6 +3581,26 @@
|
||||
"jsdoc/implements-on-classes": {
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
"jsdoc/no-blank-blocks": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowWarnDeny"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/NoBlankBlocks"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"jsdoc/no-defaults": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -13770,6 +13790,18 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"NoBlankBlocks": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enableFixer": {
|
||||
"description": "Whether to automatically remove blank JSDoc blocks.",
|
||||
"default": false,
|
||||
"type": "boolean",
|
||||
"markdownDescription": "Whether to automatically remove blank JSDoc blocks."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"NoCallbackInPromiseConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -282,6 +282,7 @@ jsdoc/check-property-names | 7
|
||||
jsdoc/check-tag-names | 7
|
||||
jsdoc/empty-tags | 7
|
||||
jsdoc/implements-on-classes | 16812
|
||||
jsdoc/no-blank-blocks | 7
|
||||
jsdoc/no-defaults | 16812
|
||||
jsdoc/require-param | 16812
|
||||
jsdoc/require-param-description | 16812
|
||||
|
||||
Reference in new issue
Block a user