Yuji Sugiura 2024-04-17 17:31:39 +09:00 committed by GitHub
parent 722d4c2350
commit 5d89e75e48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 637 additions and 0 deletions

View file

@ -362,6 +362,9 @@ mod jsdoc {
pub mod check_property_names;
pub mod empty_tags;
pub mod require_property;
pub mod require_property_description;
pub mod require_property_name;
pub mod require_property_type;
}
mod tree_shaking {
@ -690,5 +693,8 @@ oxc_macros::declare_all_lint_rules! {
jsdoc::check_property_names,
jsdoc::empty_tags,
jsdoc::require_property,
jsdoc::require_property_type,
jsdoc::require_property_name,
jsdoc::require_property_description,
tree_shaking::no_side_effects_in_initialization,
}

View file

@ -0,0 +1,192 @@
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-jsdoc(require-property-description): Missing description in @property tag.")]
#[diagnostic(severity(warning), help("Add a description to this @property tag."))]
struct RequirePropertyDescriptionDiagnostic(#[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct RequirePropertyDescription;
declare_oxc_lint!(
/// ### What it does
/// Requires that all `@property` tags have descriptions.
///
/// ### Why is this bad?
/// The description of a property should be documented.
///
/// ### Example
/// ```javascript
/// // Passing
/// /**
/// * @typedef {SomeType} SomeTypedef
/// * @property {number} foo Foo.
/// */
///
/// // Failing
/// /**
/// * @typedef {SomeType} SomeTypedef
/// * @property {number} foo
/// */
/// ```
RequirePropertyDescription,
correctness
);
impl Rule for RequirePropertyDescription {
fn run_once(&self, ctx: &LintContext) {
let settings = &ctx.settings().jsdoc;
let resolved_property_tag_name = settings.resolve_tag_name("property");
for jsdoc in ctx.semantic().jsdoc().iter_all() {
for tag in jsdoc.tags() {
let tag_kind = tag.kind;
if tag_kind.parsed() != resolved_property_tag_name {
continue;
}
let (_, _, comment_part) = tag.type_name_comment();
if !comment_part.parsed().is_empty() {
continue;
};
ctx.diagnostic(RequirePropertyDescriptionDiagnostic(tag_kind.span));
}
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
(
"
/**
* @typedef {SomeType} SomeTypedef
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property foo Foo.
*/
",
None,
None,
),
(
"
/**
* @namespace {SomeType} SomeName
* @property foo Foo.
*/
",
None,
None,
),
(
"
/**
* @class
* @property foo Foo.
*/
",
None,
None,
),
(
"
/**
* Typedef with multi-line property type.
*
* @typedef {object} MyType
* @property {function(
* number
* )} numberEater Method which takes a number.
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @prop foo ok
*/
",
None,
Some(serde_json::json!({
"jsdoc": {
"tagNamePreference": {
"property": "prop",
},
},
})),
),
];
let fail = vec![
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property foo
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property {string}
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property {string} foo
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @prop foo
*/
",
None,
Some(serde_json::json!({
"jsdoc": {
"tagNamePreference": {
"property": "prop",
},
},
})),
),
];
Tester::new(RequirePropertyDescription::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,153 @@
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-jsdoc(require-property-name): Missing name in @property tag.")]
#[diagnostic(severity(warning), help("Add a type name to this @property tag."))]
struct RequirePropertyNameDiagnostic(#[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct RequirePropertyName;
declare_oxc_lint!(
/// ### What it does
/// Requires that all `@property` tags have names.
///
/// ### Why is this bad?
/// The name of a property type should be documented.
///
/// ### Example
/// ```javascript
/// // Passing
/// /**
/// * @typedef {SomeType} SomeTypedef
/// * @property {number} foo
/// */
///
/// // Failing
/// /**
/// * @typedef {SomeType} SomeTypedef
/// * @property {number}
/// */
/// ```
RequirePropertyName,
correctness
);
impl Rule for RequirePropertyName {
fn run_once(&self, ctx: &LintContext) {
let settings = &ctx.settings().jsdoc;
let resolved_property_tag_name = settings.resolve_tag_name("property");
for jsdoc in ctx.semantic().jsdoc().iter_all() {
for tag in jsdoc.tags() {
let tag_kind = tag.kind;
if tag_kind.parsed() != resolved_property_tag_name {
continue;
}
let (_, name_part, _) = tag.type_name_comment();
if name_part.is_some() {
continue;
};
ctx.diagnostic(RequirePropertyNameDiagnostic(tag_kind.span));
}
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property foo
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property {string} foo
*/
",
None,
None,
),
(
"
/**
* @namespace {SomeType} SomeName
* @property {string} foo
*/
",
None,
None,
),
(
"
/**
* @class
* @property {string} foo
*/
",
None,
None,
),
];
let fail = vec![
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property {string}
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @prop {string}
*/
",
None,
Some(serde_json::json!({
"jsdoc": {
"tagNamePreference": {
"property": "prop",
},
},
})),
),
];
Tester::new(RequirePropertyName::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,178 @@
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-jsdoc(require-property-type): Missing type in @property tag.")]
#[diagnostic(severity(warning), help("Add a {{type}} to this @property tag."))]
struct RequirePropertyTypeDiagnostic(#[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct RequirePropertyType;
declare_oxc_lint!(
/// ### What it does
/// Requires that each `@property` tag has a type value (within curly brackets).
///
/// ### Why is this bad?
/// The type of a property should be documented.
///
/// ### Example
/// ```javascript
/// // Passing
/// /**
/// * @typedef {SomeType} SomeTypedef
/// * @property {number} foo
/// */
///
/// // Failing
/// /**
/// * @typedef {SomeType} SomeTypedef
/// * @property foo
/// */
/// ```
RequirePropertyType,
correctness
);
impl Rule for RequirePropertyType {
fn run_once(&self, ctx: &LintContext) {
let settings = &ctx.settings().jsdoc;
let resolved_property_tag_name = settings.resolve_tag_name("property");
for jsdoc in ctx.semantic().jsdoc().iter_all() {
for tag in jsdoc.tags() {
let tag_kind = tag.kind;
if tag_kind.parsed() != resolved_property_tag_name {
continue;
}
let (type_part, _, _) = tag.type_name_comment();
if type_part.is_some() {
continue;
};
ctx.diagnostic(RequirePropertyTypeDiagnostic(tag_kind.span));
}
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
(
"
/**
* @typedef {SomeType} SomeTypedef
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property {number} foo
*/
",
None,
None,
),
(
"
/**
* @namespace {SomeType} SomeName
* @property {number} foo
*/
",
None,
None,
),
(
"
/**
* @class
* @property {number} foo
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @prop {string} foo
*/
",
None,
Some(serde_json::json!({
"jsdoc": {
"tagNamePreference": {
"property": "prop",
},
},
})),
),
];
let fail = vec![
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property foo
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @property foo bar
*/
",
None,
None,
),
(
"
/**
* @typedef {SomeType} SomeTypedef
* @prop foo
*/
",
None,
Some(serde_json::json!({
"jsdoc": {
"tagNamePreference": {
"property": "prop",
},
},
})),
),
];
Tester::new(RequirePropertyType::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,39 @@
---
source: crates/oxc_linter/src/tester.rs
expression: require_property_description
---
⚠ eslint-plugin-jsdoc(require-property-description): Missing description in @property tag.
╭─[require_property_description.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property foo
· ─────────
5 │ */
╰────
help: Add a description to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-description): Missing description in @property tag.
╭─[require_property_description.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property {string}
· ─────────
5 │ */
╰────
help: Add a description to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-description): Missing description in @property tag.
╭─[require_property_description.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property {string} foo
· ─────────
5 │ */
╰────
help: Add a description to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-description): Missing description in @property tag.
╭─[require_property_description.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @prop foo
· ─────
5 │ */
╰────
help: Add a description to this @property tag.

View file

@ -0,0 +1,30 @@
---
source: crates/oxc_linter/src/tester.rs
expression: require_property_name
---
⚠ eslint-plugin-jsdoc(require-property-name): Missing name in @property tag.
╭─[require_property_name.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property
· ─────────
5 │ */
╰────
help: Add a type name to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-name): Missing name in @property tag.
╭─[require_property_name.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property {string}
· ─────────
5 │ */
╰────
help: Add a type name to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-name): Missing name in @property tag.
╭─[require_property_name.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @prop {string}
· ─────
5 │ */
╰────
help: Add a type name to this @property tag.

View file

@ -0,0 +1,39 @@
---
source: crates/oxc_linter/src/tester.rs
expression: require_property_type
---
⚠ eslint-plugin-jsdoc(require-property-type): Missing type in @property tag.
╭─[require_property_type.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property
· ─────────
5 │ */
╰────
help: Add a {type} to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-type): Missing type in @property tag.
╭─[require_property_type.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property foo
· ─────────
5 │ */
╰────
help: Add a {type} to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-type): Missing type in @property tag.
╭─[require_property_type.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @property foo bar
· ─────────
5 │ */
╰────
help: Add a {type} to this @property tag.
⚠ eslint-plugin-jsdoc(require-property-type): Missing type in @property tag.
╭─[require_property_type.tsx:4:17]
3 │ * @typedef {SomeType} SomeTypedef
4 │ * @prop foo
· ─────
5 │ */
╰────
help: Add a {type} to this @property tag.