Skip to content

Commit

Permalink
feat(require-returns): per-context forceRequireReturn; fixes #757
Browse files Browse the repository at this point in the history
  • Loading branch information
brettz9 committed May 31, 2023
1 parent 034ade1 commit 31b3a24
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 69 deletions.
27 changes: 27 additions & 0 deletions docs/rules/require-returns.md
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,20 @@ export default async function demo() {
return true;
}
// Message: Missing JSDoc @returns declaration.

/**
*
*/
function quux () {}

class Test {
/**
*
*/
abstract Test(): string;
}
// "jsdoc/require-returns": ["error"|"warn", {"contexts":["FunctionDeclaration",{"context":"TSEmptyBodyFunctionExpression","forceRequireReturn":true}]}]
// Message: Missing JSDoc @returns declaration.
````


Expand Down Expand Up @@ -1160,5 +1174,18 @@ export function readFixture(path: string): void;
* Reads a test fixture.
*/
export function readFixture(path: string);

/**
*
*/
function quux () {}

class Test {
/**
* @returns {string} The test value
*/
abstract Test(): string;
}
// "jsdoc/require-returns": ["error"|"warn", {"contexts":["FunctionDeclaration",{"context":"TSEmptyBodyFunctionExpression","forceRequireReturn":true}]}]
````

56 changes: 49 additions & 7 deletions src/iterateJsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
stringify as commentStringify,
util,
} from 'comment-parser';
import esquery from 'esquery';

/**
* @typedef {number} Integer
Expand All @@ -26,7 +27,8 @@ import {
* tags?: string[],
* replacement?: string,
* minimum?: Integer,
* message?: string
* message?: string,
* forceRequireReturn?: boolean
* }} ContextObject
*/
/**
Expand Down Expand Up @@ -467,6 +469,16 @@ import {
* @returns {boolean}
*/

/**
* @callback FindContext
* @param {Context[]} contexts
* @param {string|undefined} comment
* @returns {{
* foundContext: Context|undefined,
* contextStr: string
* }}
*/

/**
* @typedef {BasicUtils & {
* isIteratingFunction: IsIteratingFunction,
Expand Down Expand Up @@ -526,7 +538,8 @@ import {
* hasOptionTag: HasOptionTag,
* getClassNode: GetClassNode,
* getClassJsdoc: GetClassJsdoc,
* classHasTag: ClassHasTag
* classHasTag: ClassHasTag,
* findContext: FindContext
* }} Utils
*/

Expand Down Expand Up @@ -1712,6 +1725,39 @@ const getUtils = (
}
};

/** @type {FindContext} */
utils.findContext = (contexts, comment) => {
const foundContext = contexts.find((cntxt) => {
return typeof cntxt === 'string' ?
esquery.matches(
/** @type {Node} */ (node),
esquery.parse(cntxt),
undefined,
{
visitorKeys: sourceCode.visitorKeys,
},
) :
(!cntxt.context || cntxt.context === 'any' ||
esquery.matches(
/** @type {Node} */ (node),
esquery.parse(cntxt.context),
undefined,
{
visitorKeys: sourceCode.visitorKeys,
},
)) && comment === cntxt.comment;
});

const contextStr = typeof foundContext === 'object' ?
foundContext.context ?? 'any' :
String(foundContext);

return {
contextStr,
foundContext,
};
};

return utils;
};

Expand Down Expand Up @@ -1938,7 +1984,6 @@ const makeReport = (context, commentNode) => {
* @param {JsdocBlockWithInline} jsdoc
* @param {RuleConfig} ruleConfig
* @param {import('eslint').Rule.RuleContext} context
* @param {string[]} lines
* @param {import('@es-joy/jsdoccomment').Token} jsdocNode
* @param {Node|null} node
* @param {Settings} settings
Expand All @@ -1951,7 +1996,7 @@ const makeReport = (context, commentNode) => {
const iterate = (
info,
indent, jsdoc,
ruleConfig, context, lines, jsdocNode, node, settings,
ruleConfig, context, jsdocNode, node, settings,
sourceCode, iterator, state, iteratingAll,
) => {
const jsdocNde = /** @type {unknown} */ (jsdocNode);
Expand Down Expand Up @@ -2145,7 +2190,6 @@ const iterateAllJsdocs = (iterator, ruleConfig, contexts, additiveCommentContext
jsdoc,
ruleConfig,
context,
lines,
jsdocNode,
/** @type {Node} */
(node),
Expand Down Expand Up @@ -2188,7 +2232,6 @@ const iterateAllJsdocs = (iterator, ruleConfig, contexts, additiveCommentContext
jsdoc,
ruleConfig,
context,
lines,
jsdocNode,
node,
/** @type {Settings} */
Expand Down Expand Up @@ -2448,7 +2491,6 @@ export default function iterateJsdoc (iterator, ruleConfig) {
jsdoc,
ruleConfig,
context,
lines,
jsdocNode,
node,
settings,
Expand Down
31 changes: 4 additions & 27 deletions src/rules/noMissingSyntax.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import iterateJsdoc from '../iterateJsdoc';
import esquery from 'esquery';

/**
* @typedef {{
Expand Down Expand Up @@ -44,12 +43,11 @@ const incrementSelector = (state, selector, comment) => {

export default iterateJsdoc(({
context,
node,
info: {
comment,
},
sourceCode,
state,
utils,
}) => {
if (!context.options[0]) {
// Handle error later
Expand All @@ -61,30 +59,9 @@ export default iterateJsdoc(({
*/
const contexts = context.options[0].contexts;

const foundContext = contexts.find((cntxt) => {
return typeof cntxt === 'string' ?
esquery.matches(
/** @type {import('../iterateJsdoc.js').Node} */ (node),
esquery.parse(cntxt),
undefined,
{
visitorKeys: sourceCode.visitorKeys,
},
) :
(!cntxt.context || cntxt.context === 'any' ||
esquery.matches(
/** @type {import('../iterateJsdoc.js').Node} */ (node),
esquery.parse(cntxt.context),
undefined,
{
visitorKeys: sourceCode.visitorKeys,
},
)) && comment === cntxt.comment;
});

const contextStr = typeof foundContext === 'object' ?
foundContext.context ?? 'any' :
String(foundContext);
const {
contextStr,
} = utils.findContext(contexts, comment);

setDefaults(state);

Expand Down
42 changes: 8 additions & 34 deletions src/rules/noRestrictedSyntax.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import iterateJsdoc from '../iterateJsdoc';
import esquery from 'esquery';

export default iterateJsdoc(({
node,
context,
info: {
comment,
},
sourceCode,
report,
utils,
}) => {
if (!context.options.length) {
report('Rule `no-restricted-syntax` is missing a `contexts` option.');
Expand All @@ -20,44 +18,20 @@ export default iterateJsdoc(({
contexts,
} = context.options[0];

const foundContext = contexts.find(
/**
* @param {string|{context: string, comment: string}} cntxt
* @returns {boolean}
*/
(cntxt) => {
return typeof cntxt === 'string' ?
esquery.matches(
/** @type {import('../iterateJsdoc.js').Node} */ (node),
esquery.parse(cntxt),
undefined,
{
visitorKeys: sourceCode.visitorKeys,
},
) :
(!cntxt.context || cntxt.context === 'any' ||
esquery.matches(
/** @type {import('../iterateJsdoc.js').Node} */ (node),
esquery.parse(cntxt.context),
undefined,
{
visitorKeys: sourceCode.visitorKeys,
},
)) &&
comment === cntxt.comment;
},
);
const {
foundContext,
contextStr,
} = utils.findContext(contexts, comment);

// We are not on the *particular* matching context/comment, so don't assume
// we need reporting
if (!foundContext) {
return;
}

const contextStr = typeof foundContext === 'object' ?
foundContext.context ?? 'any' :
foundContext;
const message = foundContext?.message ??
const message = /** @type {import('../iterateJsdoc.js').ContextObject} */ (
foundContext
)?.message ??
'Syntax is restricted: {{context}}' +
(comment ? ' with {{comment}}' : '');

Expand Down
20 changes: 19 additions & 1 deletion src/rules/requireReturns.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ const canSkip = (utils) => {
};

export default iterateJsdoc(({
info: {
comment,
},
report,
utils,
context,
}) => {
const {
contexts,
forceRequireReturn = false,
forceReturnsWithAsync = false,
} = context.options[0] || {};
Expand All @@ -50,6 +54,17 @@ export default iterateJsdoc(({
return;
}

/** @type {boolean|undefined} */
let forceRequireReturnContext;
if (contexts) {
const {
foundContext,
} = utils.findContext(contexts, comment);
if (typeof foundContext === 'object') {
forceRequireReturnContext = foundContext.forceRequireReturn;
}
}

const tagName = /** @type {string} */ (utils.getPreferredTagName({
tagName: 'returns',
}));
Expand All @@ -76,7 +91,7 @@ export default iterateJsdoc(({
return false;
}

if (forceRequireReturn && (
if ((forceRequireReturn || forceRequireReturnContext) && (
iteratingFunction || utils.isVirtualFunction()
)) {
return true;
Expand Down Expand Up @@ -131,6 +146,9 @@ export default iterateJsdoc(({
context: {
type: 'string',
},
forceRequireReturn: {
type: 'boolean',
},
},
type: 'object',
},
Expand Down
Loading

0 comments on commit 31b3a24

Please sign in to comment.