Skip to content

Commit 68bf6cd

Browse files
committed
feat(require-property); add rule to check for property on typedef or namespace where the type is object; fixes #410
BREAKING CHANGE: Adds new rule to `recommended` config.
1 parent fb5860b commit 68bf6cd

File tree

7 files changed

+320
-0
lines changed

7 files changed

+320
-0
lines changed

.README/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ only (e.g., to match `Array` if the type is `Array` vs. `Array.<string>`).
352352
{"gitdown": "include", "file": "./rules/require-param-name.md"}
353353
{"gitdown": "include", "file": "./rules/require-param-type.md"}
354354
{"gitdown": "include", "file": "./rules/require-param.md"}
355+
{"gitdown": "include", "file": "./rules/require-property.md"}
355356
{"gitdown": "include", "file": "./rules/require-returns-check.md"}
356357
{"gitdown": "include", "file": "./rules/require-returns-description.md"}
357358
{"gitdown": "include", "file": "./rules/require-returns-type.md"}

.README/rules/require-property.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
### `require-property`
2+
3+
Requires that all `@typedef` and `@namespace` tags have `@property`
4+
when their type is a plain `object`, `Object`, or `PlainObject`.
5+
6+
Note that if any other type, including a subtype of object such as
7+
`object<string, string>`, will not be reported.
8+
9+
#### Fixer
10+
11+
The fixer for `require-example` will add an empty `@property`.
12+
13+
|||
14+
|---|---|
15+
|Context|Everywhere|
16+
|Tags|`typedef`, `namespace`|
17+
18+
<!-- assertions requireProperty -->

README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ JSDoc linting rules for ESLint.
4444
* [`require-param-name`](#eslint-plugin-jsdoc-rules-require-param-name)
4545
* [`require-param-type`](#eslint-plugin-jsdoc-rules-require-param-type)
4646
* [`require-param`](#eslint-plugin-jsdoc-rules-require-param)
47+
* [`require-property`](#eslint-plugin-jsdoc-rules-require-property)
4748
* [`require-returns-check`](#eslint-plugin-jsdoc-rules-require-returns-check)
4849
* [`require-returns-description`](#eslint-plugin-jsdoc-rules-require-returns-description)
4950
* [`require-returns-type`](#eslint-plugin-jsdoc-rules-require-returns-type)
@@ -8494,6 +8495,104 @@ export abstract class StephanPlugin<O, D> {
84948495
````
84958496

84968497

8498+
<a name="eslint-plugin-jsdoc-rules-require-property"></a>
8499+
### <code>require-property</code>
8500+
8501+
Requires that all `@typedef` and `@namespace` tags have `@property`
8502+
when their type is a plain `object`, `Object`, or `PlainObject`.
8503+
8504+
Note that if any other type, including a subtype of object such as
8505+
`object<string, string>`, will not be reported.
8506+
8507+
<a name="eslint-plugin-jsdoc-rules-require-property-fixer-1"></a>
8508+
#### Fixer
8509+
8510+
The fixer for `require-example` will add an empty `@property`.
8511+
8512+
|||
8513+
|---|---|
8514+
|Context|Everywhere|
8515+
|Tags|`typedef`, `namespace`|
8516+
8517+
The following patterns are considered problems:
8518+
8519+
````js
8520+
/**
8521+
* @typedef {object} SomeTypedef
8522+
*/
8523+
// Message: Missing JSDoc @property.
8524+
8525+
/**
8526+
* @typedef {PlainObject} SomeTypedef
8527+
*/
8528+
// Settings: {"jsdoc":{"tagNamePreference":{"property":"prop"}}}
8529+
// Message: Missing JSDoc @prop.
8530+
8531+
/**
8532+
* @namespace {Object} SomeName
8533+
*/
8534+
// Message: Missing JSDoc @property.
8535+
````
8536+
8537+
The following patterns are not considered problems:
8538+
8539+
````js
8540+
/**
8541+
*
8542+
*/
8543+
8544+
/**
8545+
* @property
8546+
*/
8547+
8548+
/**
8549+
* @typedef {Object} SomeTypedef
8550+
* @property {SomeType} propName Prop description
8551+
*/
8552+
8553+
/**
8554+
* @typedef {object} SomeTypedef
8555+
* @prop {SomeType} propName Prop description
8556+
*/
8557+
// Settings: {"jsdoc":{"tagNamePreference":{"property":"prop"}}}
8558+
8559+
/**
8560+
* @typedef {object} SomeTypedef
8561+
* @property
8562+
* // arbitrary property content
8563+
*/
8564+
8565+
/**
8566+
* @typedef {object<string, string>} SomeTypedef
8567+
*/
8568+
8569+
/**
8570+
* @typedef {string} SomeTypedef
8571+
*/
8572+
8573+
/**
8574+
* @namespace {object} SomeName
8575+
* @property {SomeType} propName Prop description
8576+
*/
8577+
8578+
/**
8579+
* @namespace {object} SomeName
8580+
* @property
8581+
* // arbitrary property content
8582+
*/
8583+
8584+
/**
8585+
* @typedef {object} SomeTypedef
8586+
* @property someProp
8587+
* @property anotherProp This with a description
8588+
* @property {anotherType} yetAnotherProp This with a type and desc.
8589+
*/
8590+
function quux () {
8591+
8592+
}
8593+
````
8594+
8595+
84978596
<a name="eslint-plugin-jsdoc-rules-require-returns-check"></a>
84988597
### <code>require-returns-check</code>
84998598

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import requireParamName from './rules/requireParamName';
2323
import requireParam from './rules/requireParam';
2424
import requireParamDescription from './rules/requireParamDescription';
2525
import requireParamType from './rules/requireParamType';
26+
import requireProperty from './rules/requireProperty';
2627
import requireReturns from './rules/requireReturns';
2728
import requireReturnsCheck from './rules/requireReturnsCheck';
2829
import requireReturnsDescription from './rules/requireReturnsDescription';
@@ -60,6 +61,7 @@ export default {
6061
'jsdoc/require-param-description': 'warn',
6162
'jsdoc/require-param-name': 'warn',
6263
'jsdoc/require-param-type': 'warn',
64+
'jsdoc/require-property': 'warn',
6365
'jsdoc/require-returns': 'warn',
6466
'jsdoc/require-returns-check': 'warn',
6567
'jsdoc/require-returns-description': 'warn',
@@ -94,6 +96,7 @@ export default {
9496
'require-param-description': requireParamDescription,
9597
'require-param-name': requireParamName,
9698
'require-param-type': requireParamType,
99+
'require-property': requireProperty,
97100
'require-returns': requireReturns,
98101
'require-returns-check': requireReturnsCheck,
99102
'require-returns-description': requireReturnsDescription,

src/rules/requireProperty.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import iterateJsdoc from '../iterateJsdoc';
2+
3+
export default iterateJsdoc(({
4+
jsdoc,
5+
utils,
6+
}) => {
7+
const propertyAssociatedTags = utils.filterTags(({tag}) => {
8+
return ['typedef', 'namespace'].includes(tag);
9+
});
10+
if (!propertyAssociatedTags.length) {
11+
return;
12+
}
13+
const targetTagName = utils.getPreferredTagName({tagName: 'property'});
14+
15+
if (utils.hasATag([targetTagName])) {
16+
return;
17+
}
18+
19+
propertyAssociatedTags.forEach((propertyAssociatedTag) => {
20+
if (!['object', 'Object', 'PlainObject'].includes(propertyAssociatedTag.type)) {
21+
return;
22+
}
23+
utils.reportJSDoc(`Missing JSDoc @${targetTagName}.`, null, () => {
24+
const line = jsdoc.tags[jsdoc.tags.length - 1].line + 1;
25+
jsdoc.tags.push({
26+
description: '',
27+
line,
28+
name: '',
29+
optional: false,
30+
tag: targetTagName,
31+
type: '',
32+
});
33+
});
34+
});
35+
}, {
36+
iterateAllJsdocs: true,
37+
meta: {
38+
fixable: 'code',
39+
type: 'suggestion',
40+
},
41+
});
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
export default {
2+
invalid: [
3+
{
4+
code: `
5+
/**
6+
* @typedef {object} SomeTypedef
7+
*/
8+
`,
9+
errors: [
10+
{
11+
message: 'Missing JSDoc @property.',
12+
},
13+
],
14+
output: `
15+
/**
16+
* @typedef {object} SomeTypedef
17+
* @property
18+
*/
19+
`,
20+
},
21+
{
22+
code: `
23+
/**
24+
* @typedef {PlainObject} SomeTypedef
25+
*/
26+
`,
27+
errors: [
28+
{
29+
message: 'Missing JSDoc @prop.',
30+
},
31+
],
32+
output: `
33+
/**
34+
* @typedef {PlainObject} SomeTypedef
35+
* @prop
36+
*/
37+
`,
38+
settings: {
39+
jsdoc: {
40+
tagNamePreference: {
41+
property: 'prop',
42+
},
43+
},
44+
},
45+
},
46+
{
47+
code: `
48+
/**
49+
* @namespace {Object} SomeName
50+
*/
51+
`,
52+
errors: [
53+
{
54+
message: 'Missing JSDoc @property.',
55+
},
56+
],
57+
output: `
58+
/**
59+
* @namespace {Object} SomeName
60+
* @property
61+
*/
62+
`,
63+
},
64+
],
65+
valid: [
66+
{
67+
code: `
68+
/**
69+
*
70+
*/
71+
`,
72+
},
73+
{
74+
code: `
75+
/**
76+
* @property
77+
*/
78+
`,
79+
},
80+
{
81+
code: `
82+
/**
83+
* @typedef {Object} SomeTypedef
84+
* @property {SomeType} propName Prop description
85+
*/
86+
`,
87+
},
88+
{
89+
code: `
90+
/**
91+
* @typedef {object} SomeTypedef
92+
* @prop {SomeType} propName Prop description
93+
*/
94+
`,
95+
settings: {
96+
jsdoc: {
97+
tagNamePreference: {
98+
property: 'prop',
99+
},
100+
},
101+
},
102+
},
103+
{
104+
code: `
105+
/**
106+
* @typedef {object} SomeTypedef
107+
* @property
108+
* // arbitrary property content
109+
*/
110+
`,
111+
},
112+
{
113+
code: `
114+
/**
115+
* @typedef {object<string, string>} SomeTypedef
116+
*/
117+
`,
118+
},
119+
{
120+
code: `
121+
/**
122+
* @typedef {string} SomeTypedef
123+
*/
124+
`,
125+
},
126+
{
127+
code: `
128+
/**
129+
* @namespace {object} SomeName
130+
* @property {SomeType} propName Prop description
131+
*/
132+
`,
133+
},
134+
{
135+
code: `
136+
/**
137+
* @namespace {object} SomeName
138+
* @property
139+
* // arbitrary property content
140+
*/
141+
`,
142+
},
143+
{
144+
code: `
145+
/**
146+
* @typedef {object} SomeTypedef
147+
* @property someProp
148+
* @property anotherProp This with a description
149+
* @property {anotherType} yetAnotherProp This with a type and desc.
150+
*/
151+
function quux () {
152+
153+
}
154+
`,
155+
},
156+
],
157+
};

test/rules/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const ruleTester = new RuleTester();
3333
'require-param-description',
3434
'require-param-name',
3535
'require-param-type',
36+
'require-property',
3637
'require-returns',
3738
'require-returns-check',
3839
'require-returns-description',

0 commit comments

Comments
 (0)