Skip to content

Commit

Permalink
fix(check-examples): preserve whitespace so as to report issues with …
Browse files Browse the repository at this point in the history
…whitespace-related rules such as `indent` (fixes gajus#211)
  • Loading branch information
brettz9 committed Jul 13, 2019
1 parent e52d763 commit 86c8b2b
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 24 deletions.
1 change: 0 additions & 1 deletion package.json
Expand Up @@ -7,7 +7,6 @@
"dependencies": {
"comment-parser": "^0.5.5",
"debug": "^4.1.1",
"escape-regex-string": "^1.0.6",
"flat-map-polyfill": "^0.3.8",
"jsdoctypeparser": "5.0.1",
"lodash": "^4.17.14",
Expand Down
52 changes: 46 additions & 6 deletions src/iterateJsdoc.js
Expand Up @@ -3,22 +3,59 @@ import commentParser from 'comment-parser';
import jsdocUtils from './jsdocUtils';
import getJSDocComment from './eslint/getJSDocComment';

const parseComment = (commentNode, indent) => {
/**
*
* @param {object} commentNode
* @param {string} indent Whitespace
* @returns {object}
*/
const parseComment = (commentNode, indent, trim = true) => {
// Preserve JSDoc block start/end indentation.
return commentParser(`${indent}/*${commentNode.value}${indent}*/`, {
// @see https://github.com/yavorskiy/comment-parser/issues/21
parsers: [
commentParser.PARSERS.parse_tag,
commentParser.PARSERS.parse_type,
(str, data) => {
if (['return', 'returns', 'throws', 'exception'].includes(data.tag)) {
if (['example', 'return', 'returns', 'throws', 'exception'].includes(data.tag)) {
return null;
}

return commentParser.PARSERS.parse_name(str, data);
},
commentParser.PARSERS.parse_description
]
trim ?
commentParser.PARSERS.parse_description :

// parse_description
(str, data) => {
// Only expected throw in previous step is if bad name (i.e.,
// missing end bracket on optional name), but `@example`
// skips name parsing
/* istanbul ignore next */
if (data.errors && data.errors.length) {
return null;
}

// Tweak original regex to capture only single optional space
const result = str.match(/^\s?((.|\s)+)?/);

// Always has at least whitespace due to `indent` we've added
/* istanbul ignore next */
if (result) {
return {
data: {
description: result[1] === undefined ? '' : result[1]
},
source: result[0]
};
}

// Always has at least whitespace due to `indent` we've added
/* istanbul ignore next */
return null;
}
],
trim
})[0] || {};
};

Expand Down Expand Up @@ -322,7 +359,7 @@ const iterateAllJsdocs = (iterator, ruleConfig) => {
}

const indent = ' '.repeat(comment.loc.start.column);
const jsdoc = parseComment(comment, indent);
const jsdoc = parseComment(comment, indent, !ruleConfig.noTrim);
const settings = getSettings(context);
const report = makeReport(context, comment);
const jsdocNode = comment;
Expand Down Expand Up @@ -368,7 +405,10 @@ export default function iterateJsdoc (iterator, ruleConfig) {
}

if (ruleConfig.iterateAllJsdocs) {
return iterateAllJsdocs(iterator, {meta: ruleConfig.meta});
return iterateAllJsdocs(iterator, {
meta: ruleConfig.meta,
noTrim: ruleConfig.noTrim
});
}

return {
Expand Down
20 changes: 7 additions & 13 deletions src/rules/checkExamples.js
@@ -1,5 +1,4 @@
import {CLIEngine, Linter} from 'eslint';
import escapeRegexString from 'escape-regex-string';
import iterateJsdoc from '../iterateJsdoc';
import warnRemovedSettings from '../warnRemovedSettings';

Expand Down Expand Up @@ -72,13 +71,9 @@ export default iterateJsdoc(({

utils.forEachPreferredTag('example', (tag, targetTagName) => {
// If a space is present, we should ignore it
const initialTag = tag.source.match(
new RegExp(`^@${escapeRegexString(targetTagName)} ?`, 'u')
);
const initialTagLength = initialTag[0].length;
const firstLinePrefixLength = preTagSpaceLength + initialTagLength;
const firstLinePrefixLength = preTagSpaceLength;

let source = tag.source.slice(initialTagLength);
let source = tag.description;
const match = source.match(hasCaptionRegex);

if (captionRequired && (!match || !match[1].trim())) {
Expand All @@ -101,16 +96,14 @@ export default iterateJsdoc(({
const idx = source.search(exampleCodeRegex);

// Strip out anything preceding user regex match (can affect line numbering)
let preMatchLines = 0;

const preMatch = source.slice(0, idx);

preMatchLines = countChars(preMatch, '\n');
const preMatchLines = countChars(preMatch, '\n');

nonJSPrefacingLines = preMatchLines;

const colDelta = preMatchLines ?
preMatch.slice(preMatch.lastIndexOf('\n') + 1).length - initialTagLength :
preMatch.slice(preMatch.lastIndexOf('\n') + 1).length :
preMatch.length;

// Get rid of text preceding user regex match (even if it leaves valid JS, it
Expand All @@ -135,7 +128,7 @@ export default iterateJsdoc(({
if (nonJSPrefaceLineCount) {
const charsInLastLine = nonJSPreface.slice(nonJSPreface.lastIndexOf('\n') + 1).length;

nonJSPrefacingCols += charsInLastLine - initialTagLength;
nonJSPrefacingCols += charsInLastLine;
} else {
nonJSPrefacingCols += colDelta + nonJSPreface.length;
}
Expand Down Expand Up @@ -277,5 +270,6 @@ export default iterateJsdoc(({
}
],
type: 'suggestion'
}
},
noTrim: true
});
29 changes: 25 additions & 4 deletions test/rules/assertions/checkExamples.js
Expand Up @@ -86,6 +86,7 @@ export default {
code: `
/**
* @example
*
* \`\`\`js alert('hello'); \`\`\`
*/
function quux () {
Expand Down Expand Up @@ -184,7 +185,7 @@ export default {
}
},
eslintrcForExamples: false,
rejectExampleCodeRegex: '^\\s*<.*>$'
rejectExampleCodeRegex: '^\\s*<.*>\\s*$'
}]
},
{
Expand Down Expand Up @@ -305,7 +306,7 @@ export default {
code: `
/**
* @example const i = 5;
* quux2()
* quux2()
*/
function quux2 () {
Expand All @@ -327,7 +328,7 @@ export default {
code: `
/**
* @example const i = 5;
* quux2()
* quux2()
*/
function quux2 () {
Expand All @@ -346,7 +347,7 @@ export default {
code: `
/**
* @example const i = 5;
* quux2()
* quux2()
*/
function quux2 () {
Expand Down Expand Up @@ -608,6 +609,26 @@ export default {
eslintrcForExamples: false,
exampleCodeRegex: '```js([\\s\\S]*)```'
}]
},
{
code: `
/**
* @example
* foo(function (err) {
* throw err;
* });
*/
function quux () {}
`,
options: [{
baseConfig: {
rules: {
indent: ['error']
}
},
eslintrcForExamples: false,
noDefaultExampleRules: false
}]
}
]
};

0 comments on commit 86c8b2b

Please sign in to comment.