📄 ban-ts-comment¶
📊 Analysis Summary¶
| Metric | Count |
|---|---|
| 🔧 Functions | 3 |
| 📦 Imports | 7 |
| 📊 Variables & Constants | 1 |
| 📐 Interfaces | 2 |
| 📑 Type Aliases | 3 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/eslint-plugin/src/rules/ban-ts-comment.ts
📤 Default Export¶
| Property | Value |
|---|---|
name |
'ban-ts-comment' |
meta.type |
'problem' |
meta.docs.description |
'Disallow @ts-<directive> comments or require descriptions after directives' |
meta.docs.recommended.recommended |
true |
meta.docs.recommended.strict |
[{ minimumDescriptionLength: 10 }] |
meta.hasSuggestions |
true |
meta.messages.replaceTsIgnoreWithTsExpectError |
'Replace "@ts-ignore" with "@ts-expect-error".' |
meta.messages.tsDirectiveComment |
'Do not use "@ts-{{directive}}" because it alters compilation errors.' |
meta.messages.tsDirectiveCommentDescriptionNotMatchPattern |
'The description for the "@ts-{{directive}}" directive must match the {{format}} format.' |
meta.messages.tsDirectiveCommentRequiresDescription |
'Include a description after the "@ts-{{directive}}" directive to explain why the @ts-{{directive}} is necessary. The... |
meta.messages.tsIgnoreInsteadOfExpectError |
'Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free.' |
meta.schema |
[ { type: 'object', $defs: { directiveConfigSchema: { oneOf: [ { type: 'boolean', default: true, }, { type: 'string',... |
defaultOptions |
[ { minimumDescriptionLength: defaultMinimumDescriptionLength, 'ts-check': false, 'ts-expect-error': 'allow-with-desc... |
Entry point: create — documented under Functions.
📦 Imports¶
| Name | Source |
|---|---|
TSESLint |
@typescript-eslint/utils |
TSESTree |
@typescript-eslint/utils |
AST_TOKEN_TYPES |
@typescript-eslint/utils |
ASTUtils |
@typescript-eslint/utils |
createRule |
../util |
getStringLength |
../util |
nullThrows |
../util |
Variables & Constants¶
| Name | Type | Kind | Value | Exported |
|---|---|---|---|---|
defaultMinimumDescriptionLe... |
3 |
const | 3 |
✗ |
Functions¶
create(context: any, [options]: any): { Program(node: any): void; }¶
Parameters:
contextany[options]any
Returns: { Program(node: any): void; }
Calls:
descriptionFormats.setregex.execnullThrows (from ../util)execDirectiveRegExcomment.value.splitnode.body.atcontext.sourceCode.getAllCommentscomments.forEachfindDirectiveInCommentcontext.reportcomment.value.replacefixer.replaceTextdescriptionFormats.getgetStringLength (from ../util)description.trimformat.test
Internal Comments:
// https://github.com/microsoft/TypeScript/blob/6f1ad5ad8bec5671f7e951a3524b62d82ec4be68/src/compiler/parser.ts#L10591 (x2)
/*
The regex used are taken from the ones used in the official TypeScript repo -
https://github.com/microsoft/TypeScript/blob/6f1ad5ad8bec5671f7e951a3524b62d82ec4be68/src/compiler/scanner.ts#L340-L348
*/ (x2)
// Special case to suggest @ts-expect-error instead of @ts-ignore (x4)
Code
create(context, [options]) {
// https://github.com/microsoft/TypeScript/blob/6f1ad5ad8bec5671f7e951a3524b62d82ec4be68/src/compiler/parser.ts#L10591
const singleLinePragmaRegEx =
/^\/\/\/?\s*@ts-(?<directive>check|nocheck)(?<description>.*)$/;
/*
The regex used are taken from the ones used in the official TypeScript repo -
https://github.com/microsoft/TypeScript/blob/6f1ad5ad8bec5671f7e951a3524b62d82ec4be68/src/compiler/scanner.ts#L340-L348
*/
const commentDirectiveRegExSingleLine =
/^\/*\s*@ts-(?<directive>expect-error|ignore)(?<description>.*)/;
const commentDirectiveRegExMultiLine =
/^\s*(?:\/|\*)*\s*@ts-(?<directive>expect-error|ignore)(?<description>.*)/;
const descriptionFormats = new Map<string, RegExp>();
for (const directive of [
'ts-expect-error',
'ts-ignore',
'ts-nocheck',
'ts-check',
] as const) {
const option = options[directive];
if (typeof option === 'object' && option.descriptionFormat) {
descriptionFormats.set(directive, new RegExp(option.descriptionFormat));
}
}
function execDirectiveRegEx(
regex: RegExp,
str: string,
): MatchedTSDirective | null {
const match = regex.exec(str);
if (!match) {
return null;
}
const { description, directive } = nullThrows(
match.groups,
'RegExp should contain groups',
);
return {
description: nullThrows(
description,
'RegExp should contain "description" group',
),
directive: nullThrows(
directive,
'RegExp should contain "directive" group',
),
};
}
function findDirectiveInComment(
comment: TSESTree.Comment,
): MatchedTSDirective | null {
if (comment.type === AST_TOKEN_TYPES.Line) {
const matchedPragma = execDirectiveRegEx(
singleLinePragmaRegEx,
`//${comment.value}`,
);
if (matchedPragma) {
return matchedPragma;
}
return execDirectiveRegEx(
commentDirectiveRegExSingleLine,
comment.value,
);
}
const commentLines = comment.value.split(ASTUtils.LINEBREAK_MATCHER);
return execDirectiveRegEx(
commentDirectiveRegExMultiLine,
commentLines[commentLines.length - 1],
);
}
return {
Program(node): void {
const firstStatement = node.body.at(0);
const comments = context.sourceCode.getAllComments();
comments.forEach(comment => {
const match = findDirectiveInComment(comment);
if (!match) {
return;
}
const { description, directive } = match;
if (
directive === 'nocheck' &&
firstStatement &&
firstStatement.loc.start.line <= comment.loc.start.line
) {
return;
}
const fullDirective = `ts-${directive}` as keyof OptionsShape;
const option = options[fullDirective];
if (option === true) {
if (directive === 'ignore') {
// Special case to suggest @ts-expect-error instead of @ts-ignore
context.report({
node: comment,
messageId: 'tsIgnoreInsteadOfExpectError',
suggest: [
{
messageId: 'replaceTsIgnoreWithTsExpectError',
fix(fixer): TSESLint.RuleFix {
const commentText = comment.value.replace(
/@ts-ignore/,
'@ts-expect-error',
);
return fixer.replaceText(
comment,
comment.type === AST_TOKEN_TYPES.Line
? `//${commentText}`
: `/*${commentText}*/`,
);
},
},
],
});
} else {
context.report({
node: comment,
messageId: 'tsDirectiveComment',
data: { directive },
});
}
}
if (
option === 'allow-with-description' ||
(typeof option === 'object' && option.descriptionFormat)
) {
const { minimumDescriptionLength } = options;
const format = descriptionFormats.get(fullDirective);
if (
getStringLength(description.trim()) <
nullThrows(
minimumDescriptionLength,
'Expected minimumDescriptionLength to be set',
)
) {
context.report({
node: comment,
messageId: 'tsDirectiveCommentRequiresDescription',
data: { directive, minimumDescriptionLength },
});
} else if (format && !format.test(description)) {
context.report({
node: comment,
messageId: 'tsDirectiveCommentDescriptionNotMatchPattern',
data: { directive, format: format.source },
});
}
}
});
},
};
}
Internal helpers¶
Declared inside another function in this file.
execDirectiveRegEx(regex: RegExp, str: string): MatchedTSDirective | null¶
Parameters:
regexRegExpstrstring
Returns: MatchedTSDirective | null
Calls:
regex.execnullThrows (from ../util)
Code
function execDirectiveRegEx(
regex: RegExp,
str: string,
): MatchedTSDirective | null {
const match = regex.exec(str);
if (!match) {
return null;
}
const { description, directive } = nullThrows(
match.groups,
'RegExp should contain groups',
);
return {
description: nullThrows(
description,
'RegExp should contain "description" group',
),
directive: nullThrows(
directive,
'RegExp should contain "directive" group',
),
};
}
findDirectiveInComment(comment: TSESTree.Comment): MatchedTSDirective | null¶
Parameters:
commentTSESTree.Comment
Returns: MatchedTSDirective | null
Calls:
execDirectiveRegExcomment.value.split
Code
function findDirectiveInComment(
comment: TSESTree.Comment,
): MatchedTSDirective | null {
if (comment.type === AST_TOKEN_TYPES.Line) {
const matchedPragma = execDirectiveRegEx(
singleLinePragmaRegEx,
`//${comment.value}`,
);
if (matchedPragma) {
return matchedPragma;
}
return execDirectiveRegEx(
commentDirectiveRegExSingleLine,
comment.value,
);
}
const commentLines = comment.value.split(ASTUtils.LINEBREAK_MATCHER);
return execDirectiveRegEx(
commentDirectiveRegExMultiLine,
commentLines[commentLines.length - 1],
);
}
Interfaces¶
OptionsShape¶
Interface Code
Properties¶
| Name | Type | Optional | Description |
|---|---|---|---|
minimumDescriptionLength |
number |
✓ | not shown |
'ts-check' |
DirectiveConfig |
✓ | not shown |
'ts-expect-error' |
DirectiveConfig |
✓ | not shown |
'ts-ignore' |
DirectiveConfig |
✓ | not shown |
'ts-nocheck' |
DirectiveConfig |
✓ | not shown |
MatchedTSDirective¶
Properties¶
| Name | Type | Optional | Description |
|---|---|---|---|
description |
string |
✗ | not shown |
directive |
string |
✗ | not shown |
Type Aliases¶
DirectiveConfig¶
Options¶
MessageIds¶
type MessageIds = | 'replaceTsIgnoreWithTsExpectError'
| 'tsDirectiveComment'
| 'tsDirectiveCommentDescriptionNotMatchPattern'
| 'tsDirectiveCommentRequiresDescription'
| 'tsIgnoreInsteadOfExpectError';
Generated by Syntax Scribe