Clean up suppressions and add rome-disable-next-statement
MODIFY
packages/@romejs/diagnostics/types.ts
packages/@romejs/diagnostics/types.ts
@@ -24,12 +24,15 @@ export type DiagnosticFilter = {
export type DiagnosticFilters = Array<DiagnosticFilter>;
-export type DiagnosticSuppressionType = 'current' | 'next';
+export type DiagnosticSuppressionType = 'next' | 'current' | 'range';
export type DiagnosticSuppression = {
type: DiagnosticSuppressionType;
+ filename: string;
category: string;
- loc: SourceLocation;
+ startLine: Number1;
+ endLine: Number1;
+ commentLocation: SourceLocation;
};
export type DiagnosticSuppressions = Array<DiagnosticSuppression>;

MODIFY
packages/@romejs/js-compiler/suppressions.test.md
packages/@romejs/js-compiler/suppressions.test.md
```javascript
Object {
- suppressions: Array []
diagnostics: Array [
Object {
description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
- }
- ]
+ category: 'suppressions/duplicate'
+ message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Duplicate suppression category <emphasis>foo</emphasis>'}
}
location: Object {
filename: 'unknown'
@@ -34,6 +27,28 @@ Object {
}
}
]
+ suppressions: Array [
+ Object {
+ category: 'foo'
+ endLine: 1
+ filename: 'unknown'
+ startLine: 1
+ suppressionType: 'current'
+ commentLocation: Object {
+ filename: 'unknown'
+ end: Object {
+ column: 0
+ index: 0
+ line: 1
+ }
+ start: Object {
+ column: 0
+ index: 0
+ line: 1
+ }
+ }
+ }
+ ]
}
```
@@ -41,20 +56,35 @@ Object {
```javascript
Object {
- suppressions: Array []
- diagnostics: Array [
+ diagnostics: Array []
+ suppressions: Array [
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
+ category: 'foo'
+ endLine: 1
+ filename: 'unknown'
+ startLine: 1
+ suppressionType: 'current'
+ commentLocation: Object {
+ filename: 'unknown'
+ end: Object {
+ column: 0
+ index: 0
+ line: 1
}
- ]
+ start: Object {
+ column: 0
+ index: 0
+ line: 1
}
- location: Object {
+ }
+ }
+ Object {
+ category: 'bar'
+ endLine: 1
+ filename: 'unknown'
+ startLine: 1
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -69,17 +99,32 @@ Object {
}
}
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
+ category: 'foo'
+ endLine: 2
+ filename: 'unknown'
+ startLine: 2
+ suppressionType: 'current'
+ commentLocation: Object {
+ filename: 'unknown'
+ end: Object {
+ column: 0
+ index: 0
+ line: 2
}
- ]
+ start: Object {
+ column: 0
+ index: 0
+ line: 2
}
- location: Object {
+ }
+ }
+ Object {
+ category: 'bar'
+ endLine: 2
+ filename: 'unknown'
+ startLine: 2
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -94,17 +139,32 @@ Object {
}
}
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
+ category: 'foo'
+ endLine: 3
+ filename: 'unknown'
+ startLine: 3
+ suppressionType: 'current'
+ commentLocation: Object {
+ filename: 'unknown'
+ end: Object {
+ column: 0
+ index: 0
+ line: 3
}
- ]
+ start: Object {
+ column: 0
+ index: 0
+ line: 3
}
- location: Object {
+ }
+ }
+ Object {
+ category: 'bar'
+ endLine: 3
+ filename: 'unknown'
+ startLine: 3
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -119,17 +179,32 @@ Object {
}
}
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
+ category: 'foo'
+ endLine: 4
+ filename: 'unknown'
+ startLine: 4
+ suppressionType: 'current'
+ commentLocation: Object {
+ filename: 'unknown'
+ end: Object {
+ column: 0
+ index: 0
+ line: 4
}
- ]
+ start: Object {
+ column: 0
+ index: 0
+ line: 4
}
- location: Object {
+ }
+ }
+ Object {
+ category: 'bar'
+ endLine: 4
+ filename: 'unknown'
+ startLine: 4
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -144,17 +219,32 @@ Object {
}
}
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
+ category: 'cat'
+ endLine: 4
+ filename: 'unknown'
+ startLine: 4
+ suppressionType: 'current'
+ commentLocation: Object {
+ filename: 'unknown'
+ end: Object {
+ column: 0
+ index: 0
+ line: 4
}
- ]
+ start: Object {
+ column: 0
+ index: 0
+ line: 4
}
- location: Object {
+ }
+ }
+ Object {
+ category: 'dog'
+ endLine: 4
+ filename: 'unknown'
+ startLine: 4
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -176,20 +266,15 @@ Object {
```javascript
Object {
- suppressions: Array []
- diagnostics: Array [
+ diagnostics: Array []
+ suppressions: Array [
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
- }
- ]
- }
- location: Object {
+ category: 'foo'
+ endLine: 1
+ filename: 'unknown'
+ startLine: 1
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -204,17 +289,12 @@ Object {
}
}
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
- }
- ]
- }
- location: Object {
+ category: 'foo'
+ endLine: 2
+ filename: 'unknown'
+ startLine: 2
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -229,17 +309,12 @@ Object {
}
}
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
- }
- ]
- }
- location: Object {
+ category: 'foo'
+ endLine: 3
+ filename: 'unknown'
+ startLine: 3
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -254,17 +329,12 @@ Object {
}
}
Object {
- description: Object {
- category: 'suppressions/incorrectPrefix'
- message: PARTIAL_BLESSED_DIAGNOSTIC_MESSAGE {value: 'Invalid suppression prefix <emphasis>rome-suppress</emphasis>'}
- advice: Array [
- log {
- category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
- }
- ]
- }
- location: Object {
+ category: 'foo'
+ endLine: 4
+ filename: 'unknown'
+ startLine: 4
+ suppressionType: 'current'
+ commentLocation: Object {
filename: 'unknown'
end: Object {
column: 0
@@ -295,7 +365,7 @@ Object {
advice: Array [
log {
category: 'info'
- text: 'Did you mean <emphasis>rome-suppress-next-line</emphasis>?'
+ text: 'Did you mean <emphasis>rome-disable-next-line</emphasis>?'
}
]
}

MODIFY
packages/@romejs/js-compiler/suppressions.test.ts
packages/@romejs/js-compiler/suppressions.test.ts
*/
import {test} from 'rome';
-import {extractSuppressionsFromComments} from './suppressions';
-import {CommentBlock} from '@romejs/js-ast';
+import {extractSuppressionsFromProgram} from './suppressions';
+import {AnyComment, CommentBlock, MOCK_PROGRAM, program} from '@romejs/js-ast';
import {ob1Coerce1, ob1Number0} from '@romejs/ob1';
+import CompilerContext from './lib/CompilerContext';
+
+function extractSuppressionsFromComments(comments: Array<AnyComment>) {
+ const ast = program.create({
+ ...MOCK_PROGRAM,
+ comments,
+ });
+ const context = new CompilerContext({ast});
+ return extractSuppressionsFromProgram(context, ast);
+}
function generateComment(value: string, line: number): CommentBlock {
const pos = {
@@ -34,10 +44,10 @@ test(
async (t) => {
t.snapshot(
extractSuppressionsFromComments([
- generateComment('rome-suppress foo', 1),
- generateComment('* rome-suppress foo', 2),
- generateComment(' * rome-suppress foo', 3),
- generateComment('* wow\n * rome-suppress foo', 4),
+ generateComment('rome-disable-line foo', 1),
+ generateComment('* rome-disable-line foo', 2),
+ generateComment(' * rome-disable-line foo', 3),
+ generateComment('* wow\n * rome-disable-line foo', 4),
]),
);
},
@@ -48,11 +58,11 @@ test(
async (t) => {
t.snapshot(
extractSuppressionsFromComments([
- generateComment('rome-suppress foo bar', 1),
- generateComment('* rome-suppress foo bar', 2),
- generateComment(' * rome-suppress foo bar', 3),
+ generateComment('rome-disable-line foo bar', 1),
+ generateComment('* rome-disable-line foo bar', 2),
+ generateComment(' * rome-disable-line foo bar', 3),
generateComment(
- '* wow\n * rome-suppress foo bar\n* rome-suppress cat dog',
+ '* wow\n * rome-disable-line foo bar\n* rome-disable-line cat dog',
4,
),
]),
@@ -76,7 +86,7 @@ test(
async (t) => {
t.snapshot(
extractSuppressionsFromComments([
- generateComment('rome-suppress foo foo', 1),
+ generateComment('rome-disable-line foo foo', 1),
]),
);
},

MODIFY
packages/@romejs/js-compiler/suppressions.ts
packages/@romejs/js-compiler/suppressions.ts
* LICENSE file in the root directory of this source tree.
*/
-import {AnyComment, Program} from '@romejs/js-ast';
+import {AnyComment, AnyNode, Program} from '@romejs/js-ast';
import {
DiagnosticLocation,
DiagnosticSuppression,
@@ -15,30 +15,87 @@ import {
descriptions,
} from '@romejs/diagnostics';
import {Dict} from '@romejs/typescript-helpers';
-import {ob1Add} from '@romejs/ob1';
-
-export const SUPPRESSION_NEXT_LINE_START = 'rome-suppress-next-line';
-const SUPPRESSION_CURRENT_LINE_START = 'rome-suppress-current-line';
-
-const SUPPRESSION_PREFIX_MISTAKES: Dict<string> = {
- 'rome-suppress': SUPPRESSION_NEXT_LINE_START,
- '@rome-suppress': SUPPRESSION_NEXT_LINE_START,
- 'rome-ignore': SUPPRESSION_NEXT_LINE_START,
- '@rome-ignore': SUPPRESSION_NEXT_LINE_START,
- '@rome-suppression-next-line': SUPPRESSION_NEXT_LINE_START,
- '@rome-suppression-current-line': SUPPRESSION_CURRENT_LINE_START,
+import {Number1, ob1Inc} from '@romejs/ob1';
+import CompilerContext from './lib/CompilerContext';
+import Path from './lib/Path';
+
+export const SUPPRESSION_NEXT_LINE_START = 'rome-disable-next-line';
+const SUPPRESSION_CURRENT_LINE_START = 'rome-disable-line';
+const SUPPRESSION_NEXT_STATEMENT_START = 'rome-disable-next-statement';
+
+const prefixMistakes: Dict<string> = {
+ disable: SUPPRESSION_NEXT_LINE_START,
+ suppress: SUPPRESSION_NEXT_LINE_START,
+ ignore: SUPPRESSION_NEXT_LINE_START,
+ 'next-statement': SUPPRESSION_NEXT_STATEMENT_START,
+ 'next-line': SUPPRESSION_NEXT_LINE_START,
+ line: SUPPRESSION_CURRENT_LINE_START,
+ 'current-line': SUPPRESSION_CURRENT_LINE_START,
};
+for (const key in prefixMistakes) {
+ const suggestion = prefixMistakes[key];
+ prefixMistakes[`ignore-${key}`] = suggestion;
+ prefixMistakes[`suppress-${key}`] = suggestion;
+ prefixMistakes[`disable-${key}`] = suggestion;
+}
type ExtractedSuppressions = {
suppressions: DiagnosticSuppressions;
diagnostics: Diagnostics;
};
-export function extractSuppressionsFromComment(
+type NodeToComment = Map<AnyComment, AnyNode>;
+
+// Perform a test on the comment line to see if it's a potential suppression typo
+function detectPossibleMistake(
+ line: string,
+):
+ | undefined
+ | {
+ prefix: string;
+ suggestion: string;
+ } {
+ // Match the first word
+ const prefixMatch = line.match(/^(?:[\s]+|)(.*?)[$\s]/);
+ if (prefixMatch == null) {
+ return undefined;
+ }
+
+ // Normalize the prefix, removing leading @
+ const prefix = prefixMatch[1];
+ let normalizedPrefix = prefix;
+ normalizedPrefix = normalizedPrefix.replace(/^@/, '');
+
+ // "Fast" check to ignore
+ if (!normalizedPrefix.startsWith('rome')) {
+ return undefined;
+ }
+
+ // Replace all underscores with dashes, remove leading rome and any dashes
+ normalizedPrefix = normalizedPrefix.replace(/_/g, '-');
+ normalizedPrefix = normalizedPrefix.replace(/^rome/, '');
+ normalizedPrefix = normalizedPrefix.replace(/^-+/, '');
+
+ for (const key in prefixMistakes) {
+ const suggestion = prefixMistakes[key];
+ if (normalizedPrefix.startsWith(key)) {
+ return {
+ suggestion,
+ prefix,
+ };
+ }
+ }
+
+ return undefined;
+}
+
+function extractSuppressionsFromComment(
+ context: CompilerContext,
comment: AnyComment,
+ getNodeToComment: () => NodeToComment,
): undefined | ExtractedSuppressions {
- const {loc} = comment;
- if (loc === undefined) {
+ const commentLocation = comment.loc;
+ if (commentLocation === undefined) {
return undefined;
}
@@ -54,30 +111,56 @@ export function extractSuppressionsFromComment(
for (const line of cleanLines) {
// Find suppression start
- let suppressionType: undefined | DiagnosticSuppressionType;
let matchedPrefix: undefined | string;
+ let startLine: undefined | Number1;
+ let endLine: undefined | Number1;
+ let suppressionType: undefined | DiagnosticSuppressionType;
if (line.startsWith(SUPPRESSION_CURRENT_LINE_START)) {
matchedPrefix = SUPPRESSION_CURRENT_LINE_START;
+ startLine = commentLocation.start.line;
+ endLine = startLine;
suppressionType = 'current';
}
if (line.startsWith(SUPPRESSION_NEXT_LINE_START)) {
matchedPrefix = SUPPRESSION_NEXT_LINE_START;
+ startLine = ob1Inc(commentLocation.start.line);
+ endLine = startLine;
suppressionType = 'next';
}
+ if (line.startsWith(SUPPRESSION_NEXT_STATEMENT_START)) {
+ matchedPrefix = SUPPRESSION_NEXT_STATEMENT_START;
+
+ const nodeToComment = getNodeToComment();
+ const nextNode = nodeToComment.get(comment);
+ if (nextNode === undefined || nextNode.loc === undefined) {
+ diagnostics.push({
+ description: descriptions.SUPPRESSIONS.NEXT_STATEMENT_NOT_FOUND,
+ location: commentLocation,
+ });
+ continue;
+ } else {
+ suppressionType = 'range';
+ startLine = nextNode.loc.start.line;
+ endLine = nextNode.loc.end.line;
+ }
+ }
- if (suppressionType === undefined || matchedPrefix === undefined) {
- for (const prefix in SUPPRESSION_PREFIX_MISTAKES) {
- const suggestion = SUPPRESSION_PREFIX_MISTAKES[prefix];
- if (line.startsWith(prefix)) {
+ if (
+ matchedPrefix === undefined ||
+ endLine === undefined ||
+ startLine === undefined ||
+ suppressionType === undefined
+ ) {
+ const mistake = detectPossibleMistake(line);
+ if (mistake !== undefined) {
diagnostics.push({
description: descriptions.SUPPRESSIONS.PREFIX_TYPO(
- prefix,
- suggestion,
+ mistake.prefix,
+ mistake.suggestion,
),
- location: loc,
+ location: commentLocation,
});
}
- }
continue;
}
@@ -85,7 +168,7 @@ export function extractSuppressionsFromComment(
if (lineWithoutPrefix[0] !== ' ') {
diagnostics.push({
description: descriptions.SUPPRESSIONS.MISSING_SPACE,
- location: loc,
+ location: commentLocation,
});
continue;
}
@@ -108,15 +191,18 @@ export function extractSuppressionsFromComment(
if (suppressedCategories.has(category)) {
diagnostics.push({
description: descriptions.SUPPRESSIONS.DUPLICATE(category),
- location: loc,
+ location: commentLocation,
});
} else {
suppressedCategories.add(category);
suppressions.push({
- type: suppressionType,
+ suppressionType,
+ filename: context.filename,
category,
- loc,
+ commentLocation,
+ startLine,
+ endLine,
});
}
@@ -133,14 +219,56 @@ export function extractSuppressionsFromComment(
}
}
-export function extractSuppressionsFromComments(
- comments: Array<AnyComment>,
+export function extractSuppressionsFromProgram(
+ context: CompilerContext,
+ ast: Program,
): ExtractedSuppressions {
+ const {comments} = ast;
+
let diagnostics: Diagnostics = [];
let suppressions: DiagnosticSuppressions = [];
+ let cachedNodeToComment: undefined | NodeToComment;
+
+ // Lazily instantiate NodeToComment only when it's needed
+ function getNodeToComment(): NodeToComment {
+ if (cachedNodeToComment !== undefined) {
+ return cachedNodeToComment;
+ }
+
+ const nodeToComment: NodeToComment = new Map();
+ cachedNodeToComment = nodeToComment;
+
+ context.reduce(
+ ast,
+ {
+ name: 'extractSuppressions',
+ enter(path: Path): AnyNode {
+ const {node} = path;
+
+ for (const comment of context.comments.getCommentsFromIds(
+ node.leadingComments,
+ )) {
+ nodeToComment.set(comment, node);
+ }
+
+ return node;
+ },
+ },
+ {
+ noScopeCreation: true,
+ },
+ );
+
+ return nodeToComment;
+ }
+
for (const comment of comments) {
- const result = extractSuppressionsFromComment(comment);
+ const result = extractSuppressionsFromComment(
+ context,
+ comment,
+ getNodeToComment,
+ );
if (result !== undefined) {
diagnostics = diagnostics.concat(result.diagnostics);
suppressions = suppressions.concat(result.suppressions);
@@ -150,29 +278,15 @@ export function extractSuppressionsFromComments(
return {suppressions, diagnostics};
}
-export function extractSuppressionsFromProgram(
- ast: Program,
-): ExtractedSuppressions {
- return extractSuppressionsFromComments(ast.comments);
-}
-
export function matchesSuppression(
- loc: DiagnosticLocation,
+ {filename, start, end}: DiagnosticLocation,
suppression: DiagnosticSuppression,
): boolean {
- const targetLine =
- suppression.type === 'current'
- ? suppression.loc.end.line
- : ob1Add(suppression.loc.end.line, 1);
-
- if (
- loc.filename !== undefined &&
- loc.start !== undefined &&
- loc.filename === suppression.loc.filename &&
- loc.start.line === targetLine
- ) {
- return true;
- }
-
- return false;
+ return (
+ filename === suppression.filename &&
+ start !== undefined &&
+ end !== undefined &&
+ start.line >= suppression.startLine &&
+ end.line <= suppression.endLine
+ );
}

Clean up suppressions and add rome-disable-next-statement