Skip to content

Commit 6341e27

Browse files
committed
feat(check-types, no-undefined-types, valid-types): use mode-aware type parsing; fixes part of gajus#356; fixes gajus#495
BREAKING CHANGE: Requires Node 10+ Also: 1. Adds "permissive" mode 2. Checks "param" for valid namepaths 3. Refactors to use updated/better Node 10+ syntax/packages
1 parent 916088a commit 6341e27

14 files changed

+188
-86
lines changed

.README/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,18 @@ how many line breaks to add when a block is missing.
131131
### Mode
132132

133133
- `settings.jsdoc.mode` - Set to `jsdoc` (the default), `typescript`, or `closure`.
134+
Note that if you do not wish to use separate `.eslintrc.*` files for a project
135+
containing both JavaScript and TypeScript, you can also use [`overrides`](https://eslint.org/docs/user-guide/configuring). You may also set to `"permissive"` to
136+
try to be as accommodating to any of the styles, but this is not recommended.
134137
Currently is used for the following:
135138
- Determine valid tags for `check-tag-names`
136139
- Only check `@template` in `no-undefined-types` for types in "closure" and
137140
"typescript" modes
138141
- For type-checking rules, determine which tags will be checked for types
139142
(Closure allows types on some tags which the others do not,
140143
so these tags will additionally be checked in "closure" mode)
144+
- For type-checking rules, impacts parsing of types (through
145+
[jsdoctypeparser](https://github.com/jsdoctypeparser/jsdoctypeparser) dependency)
141146
- Check preferred tag names
142147

143148
### Alias Preference

.babelrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@babel/preset-env",
99
{
1010
"targets": {
11-
"node": 8
11+
"node": 10
1212
}
1313
}
1414
]

.ncurc.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,5 @@ module.exports = {
44
// Whitelist all for checking besides `peer` which indicates
55
// somewhat older versions of `eslint` we still support even
66
// while our devDeps point to a more recent version
7-
dep: 'prod,dev,optional,bundle',
8-
reject: [
9-
// Todo[engine:node@>=10.0.0]: 7.0.0 of semver has minimum of Node 10
10-
'semver'
11-
]
7+
dep: 'prod,dev,optional,bundle'
128
};

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ node_js:
33
- 14
44
- 12
55
- 10
6-
- 8
76
before_install:
87
- npm config set depth 0
98
before_script: >

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,13 +189,18 @@ how many line breaks to add when a block is missing.
189189
### Mode
190190

191191
- `settings.jsdoc.mode` - Set to `jsdoc` (the default), `typescript`, or `closure`.
192+
Note that if you do not wish to use separate `.eslintrc.*` files for a project
193+
containing both JavaScript and TypeScript, you can also use [`overrides`](https://eslint.org/docs/user-guide/configuring). You may also set to `"permissive"` to
194+
try to be as accommodating to any of the styles, but this is not recommended.
192195
Currently is used for the following:
193196
- Determine valid tags for `check-tag-names`
194197
- Only check `@template` in `no-undefined-types` for types in "closure" and
195198
"typescript" modes
196199
- For type-checking rules, determine which tags will be checked for types
197200
(Closure allows types on some tags which the others do not,
198201
so these tags will additionally be checked in "closure" mode)
202+
- For type-checking rules, impacts parsing of types (through
203+
[jsdoctypeparser](https://github.com/jsdoctypeparser/jsdoctypeparser) dependency)
199204
- Check preferred tag names
200205

201206
<a name="eslint-plugin-jsdoc-settings-alias-preference"></a>
@@ -13273,6 +13278,14 @@ function quux() {
1327313278
}
1327413279
// Message: Syntax error in namepath: module:namespace.SomeClass<~
1327513280
13281+
/**
13282+
* @param someParam<~
13283+
*/
13284+
function quux() {
13285+
13286+
}
13287+
// Message: Syntax error in namepath: someParam<~
13288+
1327613289
/**
1327713290
* @memberof module:namespace.SomeClass~<
1327813291
*/
@@ -13408,6 +13421,15 @@ function quux () {}
1340813421
let foo;
1340913422
// Settings: {"jsdoc":{"mode":"closure"}}
1341013423
// Message: Tag @this must have a type
13424+
13425+
/**
13426+
* Foo function.
13427+
*
13428+
* @param {[number, string]} bar - The bar array.
13429+
*/
13430+
function foo(bar) {}
13431+
// Settings: {"jsdoc":{"mode":"jsdoc"}}
13432+
// Message: Syntax error in type: [number, string]
1341113433
````
1341213434
1341313435
The following patterns are not considered problems:
@@ -13582,6 +13604,22 @@ function quux () {}
1358213604
* @define
1358313605
*/
1358413606
function quux () {}
13607+
13608+
/**
13609+
* Foo function.
13610+
*
13611+
* @param {[number, string]} bar - The bar array.
13612+
*/
13613+
function foo(bar) {}
13614+
// Settings: {"jsdoc":{"mode":"typescript"}}
13615+
13616+
/**
13617+
* Foo function.
13618+
*
13619+
* @param {[number, string]} bar - The bar array.
13620+
*/
13621+
function foo(bar) {}
13622+
// Settings: {"jsdoc":{"mode":"permissive"}}
1358513623
````
1358613624
1358713625

package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,39 @@
77
"dependencies": {
88
"comment-parser": "^0.7.5",
99
"debug": "^4.1.1",
10-
"jsdoctypeparser": "^6.1.0",
10+
"jsdoctypeparser": "^7.0.0",
1111
"lodash": "^4.17.15",
1212
"regextras": "^0.7.1",
13-
"semver": "^6.3.0",
13+
"semver": "^7.3.2",
1414
"spdx-expression-parse": "^3.0.1"
1515
},
1616
"description": "JSDoc linting rules for ESLint.",
1717
"devDependencies": {
18-
"@babel/cli": "^7.10.1",
19-
"@babel/core": "^7.10.2",
20-
"@babel/node": "^7.10.1",
18+
"@babel/cli": "^7.10.3",
19+
"@babel/core": "^7.10.3",
20+
"@babel/node": "^7.10.3",
2121
"@babel/plugin-transform-flow-strip-types": "^7.10.1",
22-
"@babel/preset-env": "^7.10.2",
23-
"@babel/register": "^7.10.1",
24-
"@typescript-eslint/parser": "^3.2.0",
22+
"@babel/preset-env": "^7.10.3",
23+
"@babel/register": "^7.10.3",
24+
"@typescript-eslint/parser": "^3.3.0",
2525
"babel-eslint": "^10.1.0",
2626
"babel-plugin-add-module-exports": "^1.0.2",
2727
"babel-plugin-istanbul": "^6.0.0",
2828
"chai": "^4.2.0",
2929
"cross-env": "^7.0.2",
30-
"eslint": "7.2.0",
31-
"eslint-config-canonical": "^20.0.5",
30+
"eslint": "7.3.0",
31+
"eslint-config-canonical": "^20.0.6",
3232
"gitdown": "^3.1.3",
3333
"glob": "^7.1.6",
3434
"husky": "^4.2.5",
35-
"mocha": "^7.2.0",
35+
"mocha": "^8.0.1",
3636
"nyc": "^15.1.0",
3737
"rimraf": "^3.0.2",
3838
"semantic-release": "^17.0.8",
3939
"typescript": "^3.9.5"
4040
},
4141
"engines": {
42-
"node": ">=8"
42+
"node": ">=10"
4343
},
4444
"husky": {
4545
"hooks": {

src/bin/generateReadme.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import glob from 'glob';
88
import Gitdown from 'gitdown';
99

1010
const trimCode = (code) => {
11-
// todo[engine:node@>10]: Change to `trimEnd`
12-
// eslint-disable-next-line unicorn/prefer-trim-start-end
13-
let lines = code.replace(/^\n/u, '').trimRight().split('\n');
11+
let lines = code.replace(/^\n/u, '').trimEnd().split('\n');
1412

1513
const firsLineIndentation = lines[0].match(/^\s+/u);
1614
const lastLineIndentation = lines[lines.length - 1].match(/^\s+/u);

src/jsdocUtils.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ const getTagNamesForMode = (mode, context) => {
195195
return jsdocTags;
196196
case 'typescript':
197197
return typeScriptTags;
198-
case 'closure':
198+
case 'closure': case 'permissive':
199199
return closureTags;
200200
default:
201201
if (!modeWarnSettings.hasBeenWarned(context, 'mode')) {
@@ -402,9 +402,10 @@ const namepathDefiningTags = new Set([
402402
]);
403403

404404
// The following do not seem to allow curly brackets in their doc
405-
// signature or examples (besides `modifies`)
405+
// signature or examples (besides `modifies` and `param`)
406406
const tagsWithOptionalNamePosition = new Set([
407407
...namepathDefiningTags,
408+
'param',
408409

409410
// `borrows` has a different format, however, so needs special parsing;
410411
// seems to require both, and as "namepath"'s

src/rules/checkTypes.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ const adjustNames = (type, preferred, isGenericMatch, nodeName, node, parentNode
3838
if (bracketEnd) {
3939
parentNode.meta.syntax = 'ANGLE_BRACKET';
4040
ret = preferred.slice(0, -2);
41+
} else if (
42+
parentNode.meta.syntax === 'SQUARE_BRACKET' &&
43+
(nodeName === '[]' || nodeName === 'Array')
44+
) {
45+
parentNode.meta.syntax = 'ANGLE_BRACKET';
4146
}
4247
}
4348
}
@@ -64,7 +69,7 @@ export default iterateJsdoc(({
6469
return utils.tagMightHaveTypePosition(tag.tag);
6570
});
6671

67-
const {preferredTypes} = settings;
72+
const {preferredTypes, mode} = settings;
6873
const {
6974
noDefaults,
7075
unifyParentAndChildTypeChecks,
@@ -126,7 +131,7 @@ export default iterateJsdoc(({
126131
let typeAst;
127132

128133
try {
129-
typeAst = parse(jsdocTag.type);
134+
typeAst = parse(jsdocTag.type, {mode});
130135
} catch {
131136
return;
132137
}

src/rules/noUndefinedTypes.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default iterateJsdoc(({
3030
const {definedTypes = []} = context.options[0] || {};
3131

3232
let definedPreferredTypes = [];
33-
const {preferredTypes} = settings;
33+
const {preferredTypes, mode} = settings;
3434
if (Object.keys(preferredTypes).length) {
3535
// Replace `_.values` with `Object.values` when we may start requiring Node 7+
3636
definedPreferredTypes = _.values(preferredTypes).map((preferredType) => {
@@ -139,7 +139,7 @@ export default iterateJsdoc(({
139139
let parsedType;
140140

141141
try {
142-
parsedType = parseType(tag.type);
142+
parsedType = parseType(tag.type, {mode});
143143
} catch {
144144
// On syntax error, will be handled by valid-types.
145145
return;

src/rules/requireDescriptionCompleteSentence.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ const otherDescriptiveTags = new Set([
1111
]);
1212

1313
const extractParagraphs = (text) => {
14-
// Todo [engine:node@>8.11.0]: Uncomment following line with neg. lookbehind instead
15-
// return text.split(/(?<![;:])\n\n/u);
16-
return [...text].reverse().join('').split(/\n\n(?![;:])/u).map((par) => {
17-
return [...par].reverse().join('');
18-
}).reverse();
14+
return text.split(/(?<![;:])\n\n/u);
1915
};
2016

2117
const extractSentences = (text, abbreviationsRegex) => {

src/rules/requireJsdoc.js

Lines changed: 44 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -225,67 +225,63 @@ export default {
225225
}
226226
};
227227

228-
// todo[engine:node@>=8.3.0]: Change to object spread
229-
// eslint-disable-next-line fp/no-mutating-assign
230-
return Object.assign(
231-
jsdocUtils.getContextObject(jsdocUtils.enforcedContexts(context, []), checkJsDoc),
232-
{
233-
ArrowFunctionExpression (node) {
234-
if (!requireOption.ArrowFunctionExpression) {
235-
return;
236-
}
228+
return {
229+
...jsdocUtils.getContextObject(jsdocUtils.enforcedContexts(context, []), checkJsDoc),
230+
ArrowFunctionExpression (node) {
231+
if (!requireOption.ArrowFunctionExpression) {
232+
return;
233+
}
237234

238-
if (!['VariableDeclarator', 'ExportDefaultDeclaration', 'AssignmentExpression'].includes(node.parent.type)) {
239-
return;
240-
}
235+
if (!['VariableDeclarator', 'ExportDefaultDeclaration', 'AssignmentExpression'].includes(node.parent.type)) {
236+
return;
237+
}
241238

242-
checkJsDoc(node, true);
243-
},
239+
checkJsDoc(node, true);
240+
},
244241

245-
ClassDeclaration (node) {
246-
if (!requireOption.ClassDeclaration) {
247-
return;
248-
}
242+
ClassDeclaration (node) {
243+
if (!requireOption.ClassDeclaration) {
244+
return;
245+
}
249246

250-
checkJsDoc(node);
251-
},
247+
checkJsDoc(node);
248+
},
252249

253-
ClassExpression (node) {
254-
if (!requireOption.ClassExpression) {
255-
return;
256-
}
250+
ClassExpression (node) {
251+
if (!requireOption.ClassExpression) {
252+
return;
253+
}
257254

258-
checkJsDoc(node);
259-
},
255+
checkJsDoc(node);
256+
},
260257

261-
FunctionDeclaration (node) {
262-
if (!requireOption.FunctionDeclaration) {
263-
return;
264-
}
258+
FunctionDeclaration (node) {
259+
if (!requireOption.FunctionDeclaration) {
260+
return;
261+
}
265262

266-
checkJsDoc(node, true);
267-
},
263+
checkJsDoc(node, true);
264+
},
268265

269-
FunctionExpression (node) {
270-
if (requireOption.MethodDefinition && node.parent.type === 'MethodDefinition') {
271-
checkJsDoc(node, true);
266+
FunctionExpression (node) {
267+
if (requireOption.MethodDefinition && node.parent.type === 'MethodDefinition') {
268+
checkJsDoc(node, true);
272269

273-
return;
274-
}
270+
return;
271+
}
275272

276-
if (!requireOption.FunctionExpression) {
277-
return;
278-
}
273+
if (!requireOption.FunctionExpression) {
274+
return;
275+
}
279276

280-
if (
281-
['VariableDeclarator', 'AssignmentExpression', 'ExportDefaultDeclaration'].includes(node.parent.type) ||
282-
node.parent.type === 'Property' && node === node.parent.value
283-
) {
284-
checkJsDoc(node, true);
285-
}
286-
},
277+
if (
278+
['VariableDeclarator', 'AssignmentExpression', 'ExportDefaultDeclaration'].includes(node.parent.type) ||
279+
node.parent.type === 'Property' && node === node.parent.value
280+
) {
281+
checkJsDoc(node, true);
282+
}
287283
},
288-
);
284+
};
289285
},
290286
meta: {
291287
docs: {

0 commit comments

Comments
 (0)