Skip to content

Commit c57e304

Browse files
author
[Interfaced] Кирилл Дронкин
committed
1.4.0
1 parent deb4e92 commit c57e304

17 files changed

+1266
-161
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Change log
22

3+
## 1.4.0 (release date: 9.10.2018)
4+
5+
* Preserve the head and the tail of a JSDoc
6+
* `jsdoc-type-spacing`: don't crash on an one-symbol token
7+
* New rule: `jsdoc-type-indent`
8+
39
## 1.3.0 (release date: 28.09.2018)
410

511
* `jsdoc-type-spacing`: tolerate multiline types

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ npm i eslint-plugin-interfaced --save-dev
4141
* [interfaced/interface-name-prefix](docs/rules/interface-name-prefix.md)
4242
* [interfaced/jsdoc-tags-order](docs/rules/jsdoc-tags-order.md)
4343
* [interfaced/jsdoc-type-application-dot](docs/rules/jsdoc-type-application-dot.md)
44+
* [interfaced/jsdoc-type-indent](docs/rules/jsdoc-type-indent.md)
4445
* [interfaced/jsdoc-type-spacing](docs/rules/jsdoc-type-spacing.md)
4546
* [interfaced/lines-around-class](docs/rules/lines-around-class.md)
4647
* [interfaced/lines-between-methods](docs/rules/lines-between-methods.md)

docs/rules/jsdoc-type-indent.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# interfaced/jsdoc-type-indent
2+
3+
Enforce consistent indentation in JSDocs.
4+
5+
**Fixable:** this rule is automatically fixable by `--fix`.
6+
7+
## Options
8+
9+
The rule accepts either `'tab'` for tabbed indentation or an integer for spaced indentation. The default value is `2` (2-space indentation).
10+
11+
## Resources
12+
13+
* [Source](../../lib/rules/jsdoc-type-indent.js)
14+
* [Tests](../../test/eslint/rules/jsdoc-type-indent.js)

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports.rules = {
1414
'interface-name-prefix': require('./lib/rules/interface-name-prefix'),
1515
'jsdoc-tags-order': require('./lib/rules/jsdoc-tags-order'),
1616
'jsdoc-type-application-dot': require('./lib/rules/jsdoc-type-application-dot'),
17+
'jsdoc-type-indent': require('./lib/rules/jsdoc-type-indent'),
1718
'jsdoc-type-spacing': require('./lib/rules/jsdoc-type-spacing'),
1819
'lines-around-class': require('./lib/rules/lines-around-class'),
1920
'lines-between-methods': require('./lib/rules/lines-between-methods'),

lib/ast-utils.js

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
const doctrine = require('doctrine');
22
const JSDocTokenizer = require('./jsdoc-tokenizer');
33

4-
const JSDocTypeTokenizer = new JSDocTokenizer({
5-
type: true,
6-
range: true
7-
});
4+
const JSDocTokenizers = {
5+
default: new JSDocTokenizer({
6+
range: true
7+
}),
8+
type: new JSDocTokenizer({
9+
type: true,
10+
range: true
11+
})
12+
};
813

914
/**
1015
* @param {ASTNode} node
@@ -282,7 +287,8 @@ function parseJSDoc(comment) {
282287
return null;
283288
}
284289

285-
const content = doctrine.unwrapComment(comment.value);
290+
const content = doctrine.unwrapComment(comment.value)
291+
.replace(/^\s*/, ''); // Remove heading whitespace
286292

287293
let JSDoc = null;
288294
try {
@@ -373,7 +379,7 @@ function getJSDocTypeContent(JSDoc, type) {
373379
* @return {Array<JSDocTokenWithRange>}
374380
*/
375381
function getJSDocTagTokens(JSDoc, tag) {
376-
return JSDocTypeTokenizer.tokenize(JSDoc.content.slice(...tag.range))
382+
return JSDocTokenizers.default.tokenize(JSDoc.content.slice(...tag.range))
377383
.map((token) => {
378384
token.range[0] += tag.range[0];
379385
token.range[1] += tag.range[0];
@@ -388,7 +394,7 @@ function getJSDocTagTokens(JSDoc, tag) {
388394
* @return {Array<JSDocTokenWithRange>}
389395
*/
390396
function getJSDocTypeTokens(JSDoc, type) {
391-
return JSDocTypeTokenizer.tokenize(JSDoc.content.slice(...type.range))
397+
return JSDocTokenizers.type.tokenize(JSDoc.content.slice(...type.range))
392398
.map((token) => {
393399
token.range[0] += type.range[0];
394400
token.range[1] += type.range[0];
@@ -427,6 +433,53 @@ function getJSDocTokenAfter(tokens, targetToken) {
427433
return tokens.find((token) => token.range[0] === targetToken.range[1]) || null;
428434
}
429435

436+
/**
437+
* @param {Array<JSDocTokenWithRange>} tokens
438+
* @param {JSDocTokenWithRange} tokenA
439+
* @param {JSDocTokenWithRange} tokenB
440+
* @return {Array<JSDocTokenWithRange>}
441+
*/
442+
function getJSDocTokensBetween(tokens, tokenA, tokenB) {
443+
const tokensBetween = [];
444+
445+
let cursor = tokenA;
446+
while (cursor) {
447+
cursor = getJSDocTokenAfter(tokens, cursor);
448+
449+
if (!cursor || cursor.range[0] === tokenB.range[0]) {
450+
break;
451+
}
452+
453+
tokensBetween.push(cursor);
454+
}
455+
456+
return tokensBetween;
457+
}
458+
459+
/**
460+
* @param {Array<JSDocTokenWithRange>} tokens
461+
* @param {{
462+
* type: (string|undefined),
463+
* value: (string|undefined)
464+
* }=} options
465+
* @return {?JSDocTokenWithRange}
466+
*/
467+
function findFirstJSDocToken(tokens, {type, value}) {
468+
return tokens.find((token) => (!type || token.type === type) && (!value || token.value === value)) || null;
469+
}
470+
471+
/**
472+
* @param {Array<JSDocTokenWithRange>} tokens
473+
* @param {{
474+
* type: (string|undefined),
475+
* value: (string|undefined)
476+
* }=} options
477+
* @return {?JSDocTokenWithRange}
478+
*/
479+
function findLastJSDocToken(tokens, {type, value}) {
480+
return findFirstJSDocToken(tokens.slice().reverse(), {type, value});
481+
}
482+
430483
/**
431484
* @param {Array<JSDocTokenWithRange>} tokens
432485
* @param {JSDocTokenWithRange} token
@@ -438,26 +491,22 @@ function getJSDocTokenAfter(tokens, targetToken) {
438491
* @return {?JSDocTokenWithRange}
439492
*/
440493
function findNonWhitespaceSiblingJSDocToken(tokens, token, {type, value, moveForward = true} = {}) {
441-
let currentToken = token;
442-
443-
while (currentToken) {
444-
currentToken = moveForward ?
445-
getJSDocTokenAfter(tokens, currentToken) :
446-
getJSDocTokenBefore(tokens, currentToken);
494+
let cursor = token;
495+
while (cursor) {
496+
cursor = moveForward ?
497+
getJSDocTokenAfter(tokens, cursor) :
498+
getJSDocTokenBefore(tokens, cursor);
447499

448-
if (!currentToken) {
500+
if (!cursor) {
449501
return null;
450502
}
451503

452-
if (currentToken.type === 'Whitespace') {
504+
if (cursor.type === 'Whitespace') {
453505
continue;
454506
}
455507

456-
if (
457-
(!type || currentToken.type === type) &&
458-
(!value || currentToken.value === value)
459-
) {
460-
return currentToken;
508+
if ((!type || cursor.type === type) && (!value || cursor.value === value)) {
509+
return cursor;
461510
}
462511

463512
return null;
@@ -589,8 +638,11 @@ module.exports = {
589638
getJSDocSubtypeTokens,
590639
getJSDocTokenBefore,
591640
getJSDocTokenAfter,
641+
getJSDocTokensBetween,
592642
getScopeFromJSDoc,
593643
getStaticTypeFromJSDoc,
644+
findFirstJSDocToken,
645+
findLastJSDocToken,
594646
findNonWhitespaceSiblingJSDocToken,
595647
traverseJSDocType
596648
};

lib/rules/event-const-desc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const {visitConstantExpressions} = require('../visitors');
22
const {getJSDocDescription, resolveConstantName} = require('../ast-utils');
3+
const {LINE_BREAK_MATCHER} = require('../utils');
34

45
module.exports = {
56
meta: {
@@ -19,7 +20,7 @@ module.exports = {
1920
if (constantName.startsWith('EVENT_')) {
2021
const description = getJSDocDescription(constantExpression, sourceCode);
2122

22-
if (!description.split('\n').some((line) => line.startsWith('Fired with:'))) {
23+
if (!description.split(LINE_BREAK_MATCHER).some((line) => line.startsWith('Fired with:'))) {
2324
context.report({
2425
node: constantExpression,
2526
message: `Event constant "${constantName}" has no "Fired with: ..." description.`

0 commit comments

Comments
 (0)