Skip to content

Commit 94da96c

Browse files
authored
fix: unify LintMessage type (#17076)
* Update LintMessage type to reflect implementation I made three changes to `LintMessage` and `SuppressedLintMessage` 1. Many places that create `LintMessage`s don't set `fatal`, so I made it optional. This would be a breaking change if we made types part of our exports, but in this case I believe it's updating JSDoc documentation to reflect reality. 2. Added an optional `messageId` property that's set by reports from rules. 3. Added an optional, nullable `nodeType` property. - Reports from rules set it to a value. - `applyDirectives()` explicitly sets it to `null` for unused disable directives. - `Linter`'s `createLintingProblem()` explicitly sets it to `null`. * Add missing LintResult type import * Use LintMessage type All of these previously referenced a `Problem` type that does not have a definition. * Replace ReportInfo type with LintMessage type `ReportInfo` was defined within `report-translator.js` to be very similar to `LintMessage`. It had one extra property, `source`, which wasn't ever set, so it would've been removed anyway. In `Linter.runRules()`, the return value from `reportTranslator()` gets pushed into a `lintingProblems` array and returned, and the return type annotation is `LintMessage[]`, which gives me confidence that `ReportInfo` was intended to be the same type as `LintMessage` elsewhere. * Make ruleId required but nullable Originally, we talked about the reverse - making `ruleId` optional but non-nullable and relying on `report-translator.js`'s `createProblem()` to normalize it. However, the `LintMessage` type would differ from `createProblem()`'s return value only by `null` vs `undefined` for `ruleId`. So instead, I made `ruleId` required but nullable and explicitly set it to `null` in the few remaining places that didn't already. * Add missing null nodeTypes `LintMessage.nodeType` is currently defined as required but nullable. Actual implementations explicitly set it to `null` in a couple places and omit it in several. After discussion in #16968, we initially leaned toward making it non-nullable but optional. I pursued that, but it resulted in slightly more runtime code changes, including some branching in `report-translator` to set it conditionally. Instead, I'm presenting the opposite solution of updating the remaining implementations to match the existing type definition by explicitly setting `nodeType` to `null`. * Update LintMessage docs This updates existing documented properties to match the updated `LintMessage` type and implementations. `messageId`, `nodeType`, and `suppressions` remain undocumented.
1 parent 7709b14 commit 94da96c

14 files changed

+87
-55
lines changed

Diff for: docs/src/extend/custom-processors.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,19 @@ Reported problems have the following location information in each lint message:
5959
type LintMessage = {
6060

6161
/// The 1-based line number where the message occurs.
62-
line: number;
62+
line?: number;
6363

6464
/// The 1-based column number where the message occurs.
65-
column: number;
65+
column?: number;
6666

6767
/// The 1-based line number of the end location.
68-
endLine: number;
68+
endLine?: number;
6969

7070
/// The 1-based column number of the end location.
71-
endColumn: number;
71+
endColumn?: number;
7272

7373
/// If `true`, this is a fatal error.
74-
fatal: boolean;
74+
fatal?: boolean;
7575

7676
/// Information for an autofix.
7777
fix: Fix;

Diff for: lib/cli-engine/cli-engine.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,11 @@ function createIgnoreResult(filePath, baseDir) {
308308
filePath: path.resolve(filePath),
309309
messages: [
310310
{
311+
ruleId: null,
311312
fatal: false,
312313
severity: 1,
313-
message
314+
message,
315+
nodeType: null
314316
}
315317
],
316318
suppressedMessages: [],

Diff for: lib/eslint/eslint-helpers.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -607,9 +607,11 @@ function createIgnoreResult(filePath, baseDir) {
607607
filePath: path.resolve(filePath),
608608
messages: [
609609
{
610+
ruleId: null,
610611
fatal: false,
611612
severity: 1,
612-
message
613+
message,
614+
nodeType: null
613615
}
614616
],
615617
suppressedMessages: [],

Diff for: lib/eslint/flat-eslint.js

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const LintResultCache = require("../cli-engine/lint-result-cache");
5555
/** @typedef {import("../shared/types").ConfigData} ConfigData */
5656
/** @typedef {import("../shared/types").DeprecatedRuleInfo} DeprecatedRuleInfo */
5757
/** @typedef {import("../shared/types").LintMessage} LintMessage */
58+
/** @typedef {import("../shared/types").LintResult} LintResult */
5859
/** @typedef {import("../shared/types").ParserOptions} ParserOptions */
5960
/** @typedef {import("../shared/types").Plugin} Plugin */
6061
/** @typedef {import("../shared/types").ResultsMeta} ResultsMeta */

Diff for: lib/linter/apply-disable-directives.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55

66
"use strict";
77

8+
//------------------------------------------------------------------------------
9+
// Typedefs
10+
//------------------------------------------------------------------------------
11+
12+
/** @typedef {import("../shared/types").LintMessage} LintMessage */
13+
14+
//------------------------------------------------------------------------------
15+
// Module Definition
16+
//------------------------------------------------------------------------------
17+
818
const escapeRegExp = require("escape-string-regexp");
919

1020
/**
@@ -196,7 +206,7 @@ function processUnusedDisableDirectives(allDirectives) {
196206
* @param {Object} options options for applying directives. This is the same as the options
197207
* for the exported function, except that `reportUnusedDisableDirectives` is not supported
198208
* (this function always reports unused disable directives).
199-
* @returns {{problems: Problem[], unusedDisableDirectives: Problem[]}} An object with a list
209+
* @returns {{problems: LintMessage[], unusedDisableDirectives: LintMessage[]}} An object with a list
200210
* of problems (including suppressed ones) and unused eslint-disable directives
201211
*/
202212
function applyDirectives(options) {

Diff for: lib/linter/config-comment-parser.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ const levn = require("levn"),
1919

2020
const debug = require("debug")("eslint:config-comment-parser");
2121

22+
//------------------------------------------------------------------------------
23+
// Typedefs
24+
//------------------------------------------------------------------------------
25+
26+
/** @typedef {import("../shared/types").LintMessage} LintMessage */
27+
2228
//------------------------------------------------------------------------------
2329
// Public Interface
2430
//------------------------------------------------------------------------------
@@ -61,7 +67,7 @@ module.exports = class ConfigCommentParser {
6167
* Parses a JSON-like config.
6268
* @param {string} string The string to parse.
6369
* @param {Object} location Start line and column of comments for potential error message.
64-
* @returns {({success: true, config: Object}|{success: false, error: Problem})} Result map object
70+
* @returns {({success: true, config: Object}|{success: false, error: LintMessage})} Result map object
6571
*/
6672
parseJsonConfig(string, location) {
6773
debug("Parsing JSON config");
@@ -109,7 +115,8 @@ module.exports = class ConfigCommentParser {
109115
severity: 2,
110116
message: `Failed to parse JSON from '${normalizedString}': ${ex.message}`,
111117
line: location.start.line,
112-
column: location.start.column + 1
118+
column: location.start.column + 1,
119+
nodeType: null
113120
}
114121
};
115122

Diff for: lib/linter/linter.js

+14-9
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ function extractDirectiveComment(value) {
364364
* @param {ASTNode} ast The top node of the AST.
365365
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
366366
* @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from.
367-
* @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: Problem[], disableDirectives: DisableDirective[]}}
367+
* @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: LintMessage[], disableDirectives: DisableDirective[]}}
368368
* A collection of the directive comments that were found, along with any problems that occurred when parsing
369369
*/
370370
function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
@@ -775,7 +775,7 @@ function analyzeScope(ast, languageOptions, visitorKeys) {
775775
* @param {string} text The text to parse.
776776
* @param {LanguageOptions} languageOptions Options to pass to the parser
777777
* @param {string} filePath The path to the file being parsed.
778-
* @returns {{success: false, error: Problem}|{success: true, sourceCode: SourceCode}}
778+
* @returns {{success: false, error: LintMessage}|{success: true, sourceCode: SourceCode}}
779779
* An object containing the AST and parser services if parsing was successful, or the error if parsing failed
780780
* @private
781781
*/
@@ -851,7 +851,8 @@ function parse(text, languageOptions, filePath) {
851851
severity: 2,
852852
message,
853853
line: ex.lineNumber,
854-
column: ex.column
854+
column: ex.column,
855+
nodeType: null
855856
}
856857
};
857858
}
@@ -921,7 +922,7 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
921922
* @param {boolean} disableFixes If true, it doesn't make `fix` properties.
922923
* @param {string | undefined} cwd cwd of the cli
923924
* @param {string} physicalFilename The full path of the file on disk without any code block information
924-
* @returns {Problem[]} An array of reported problems
925+
* @returns {LintMessage[]} An array of reported problems
925926
*/
926927
function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageOptions, settings, filename, disableFixes, cwd, physicalFilename) {
927928
const emitter = createEmitter();
@@ -1253,7 +1254,8 @@ class Linter {
12531254
severity: 2,
12541255
message: `Configured parser '${config.parser}' was not found.`,
12551256
line: 0,
1256-
column: 0
1257+
column: 0,
1258+
nodeType: null
12571259
}];
12581260
}
12591261
parserName = config.parser;
@@ -1464,7 +1466,8 @@ class Linter {
14641466
severity: 2,
14651467
message,
14661468
line: ex.lineNumber,
1467-
column: ex.column
1469+
column: ex.column,
1470+
nodeType: null
14681471
}
14691472
];
14701473
}
@@ -1729,7 +1732,8 @@ class Linter {
17291732
severity: 1,
17301733
message: `No matching configuration found for ${filename}.`,
17311734
line: 0,
1732-
column: 0
1735+
column: 0,
1736+
nodeType: null
17331737
}
17341738
];
17351739
}
@@ -1794,7 +1798,8 @@ class Linter {
17941798
severity: 2,
17951799
message,
17961800
line: ex.lineNumber,
1797-
column: ex.column
1801+
column: ex.column,
1802+
nodeType: null
17981803
}
17991804
];
18001805
}
@@ -1840,7 +1845,7 @@ class Linter {
18401845
/**
18411846
* Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
18421847
* The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
1843-
* @param {Problem[]} problems A list of reported problems.
1848+
* @param {Array<LintMessage|SuppressedLintMessage>} problems A list of reported problems.
18441849
* @returns {LintMessage[]} A list of LintMessage.
18451850
*/
18461851
_distinguishSuppressedMessages(problems) {

Diff for: lib/linter/report-translator.js

+4-19
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const interpolate = require("./interpolate");
1717
// Typedefs
1818
//------------------------------------------------------------------------------
1919

20+
/** @typedef {import("../shared/types").LintMessage} LintMessage */
21+
2022
/**
2123
* An error message description
2224
* @typedef {Object} MessageDescriptor
@@ -29,23 +31,6 @@ const interpolate = require("./interpolate");
2931
* @property {Array<{desc?: string, messageId?: string, fix: Function}>} suggest Suggestion descriptions and functions to create a the associated fixes.
3032
*/
3133

32-
/**
33-
* Information about the report
34-
* @typedef {Object} ReportInfo
35-
* @property {string} ruleId The rule ID
36-
* @property {(0|1|2)} severity Severity of the error
37-
* @property {(string|undefined)} message The message
38-
* @property {(string|undefined)} [messageId] The message ID
39-
* @property {number} line The line number
40-
* @property {number} column The column number
41-
* @property {(number|undefined)} [endLine] The ending line number
42-
* @property {(number|undefined)} [endColumn] The ending column number
43-
* @property {(string|null)} nodeType Type of node
44-
* @property {string} source Source text
45-
* @property {({text: string, range: (number[]|null)}|null)} [fix] The fix object
46-
* @property {Array<{text: string, range: (number[]|null)}|null>} [suggestions] Suggestion info
47-
*/
48-
4934
//------------------------------------------------------------------------------
5035
// Module Definition
5136
//------------------------------------------------------------------------------
@@ -239,7 +224,7 @@ function mapSuggestions(descriptor, sourceCode, messages) {
239224
* @param {{start: SourceLocation, end: (SourceLocation|null)}} options.loc Start and end location
240225
* @param {{text: string, range: (number[]|null)}} options.fix The fix object
241226
* @param {Array<{text: string, range: (number[]|null)}>} options.suggestions The array of suggestions objects
242-
* @returns {function(...args): ReportInfo} Function that returns information about the report
227+
* @returns {LintMessage} Information about the report
243228
*/
244229
function createProblem(options) {
245230
const problem = {
@@ -314,7 +299,7 @@ function validateSuggestions(suggest, messages) {
314299
* problem for the Node.js API.
315300
* @param {{ruleId: string, severity: number, sourceCode: SourceCode, messageIds: Object, disableFixes: boolean}} metadata Metadata for the reported problem
316301
* @param {SourceCode} sourceCode The `SourceCode` instance for the text being linted
317-
* @returns {function(...args): ReportInfo} Function that returns information about the report
302+
* @returns {function(...args): LintMessage} Function that returns information about the report
318303
*/
319304

320305
module.exports = function createReportTranslator(metadata) {

Diff for: lib/shared/types.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,12 @@ module.exports = {};
9696
* @property {number|undefined} column The 1-based column number.
9797
* @property {number} [endColumn] The 1-based column number of the end location.
9898
* @property {number} [endLine] The 1-based line number of the end location.
99-
* @property {boolean} fatal If `true` then this is a fatal error.
99+
* @property {boolean} [fatal] If `true` then this is a fatal error.
100100
* @property {{range:[number,number], text:string}} [fix] Information for autofix.
101101
* @property {number|undefined} line The 1-based line number.
102102
* @property {string} message The error message.
103+
* @property {string} [messageId] The ID of the message in the rule's meta.
104+
* @property {(string|null)} nodeType Type of node
103105
* @property {string|null} ruleId The ID of the rule which makes this message.
104106
* @property {0|1|2} severity The severity of this message.
105107
* @property {Array<{desc?: string, messageId?: string, fix: {range: [number, number], text: string}}>} [suggestions] Information for suggestions.
@@ -110,10 +112,12 @@ module.exports = {};
110112
* @property {number|undefined} column The 1-based column number.
111113
* @property {number} [endColumn] The 1-based column number of the end location.
112114
* @property {number} [endLine] The 1-based line number of the end location.
113-
* @property {boolean} fatal If `true` then this is a fatal error.
115+
* @property {boolean} [fatal] If `true` then this is a fatal error.
114116
* @property {{range:[number,number], text:string}} [fix] Information for autofix.
115117
* @property {number|undefined} line The 1-based line number.
116118
* @property {string} message The error message.
119+
* @property {string} [messageId] The ID of the message in the rule's meta.
120+
* @property {(string|null)} nodeType Type of node
117121
* @property {string|null} ruleId The ID of the rule which makes this message.
118122
* @property {0|1|2} severity The severity of this message.
119123
* @property {Array<{kind: string, justification: string}>} suppressions The suppression info.

Diff for: tests/lib/cli-engine/cli-engine.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,8 @@ describe("CLIEngine", () => {
577577
severity: 2,
578578
message: "Parsing error: Unexpected token is",
579579
line: 1,
580-
column: 19
580+
column: 19,
581+
nodeType: null
581582
}
582583
],
583584
suppressedMessages: [],
@@ -622,7 +623,8 @@ describe("CLIEngine", () => {
622623
severity: 2,
623624
message: "Parsing error: Unexpected token",
624625
line: 1,
625-
column: 10
626+
column: 10,
627+
nodeType: null
626628
}
627629
],
628630
suppressedMessages: [],
@@ -713,7 +715,8 @@ describe("CLIEngine", () => {
713715
severity: 2,
714716
message: "Parsing error: Unexpected token is",
715717
line: 1,
716-
column: 19
718+
column: 19,
719+
nodeType: null
717720
}
718721
],
719722
suppressedMessages: [],

Diff for: tests/lib/eslint/eslint.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,8 @@ describe("ESLint", () => {
690690
severity: 2,
691691
message: "Parsing error: Unexpected token is",
692692
line: 1,
693-
column: 19
693+
column: 19,
694+
nodeType: null
694695
}
695696
],
696697
suppressedMessages: [],
@@ -730,7 +731,8 @@ describe("ESLint", () => {
730731
severity: 2,
731732
message: "Parsing error: Unexpected token",
732733
line: 1,
733-
column: 10
734+
column: 10,
735+
nodeType: null
734736
}
735737
],
736738
suppressedMessages: [],
@@ -819,7 +821,8 @@ describe("ESLint", () => {
819821
severity: 2,
820822
message: "Parsing error: Unexpected token is",
821823
line: 1,
822-
column: 19
824+
column: 19,
825+
nodeType: null
823826
}
824827
],
825828
suppressedMessages: [],

Diff for: tests/lib/eslint/flat-eslint.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,8 @@ describe("FlatESLint", () => {
506506
severity: 2,
507507
message: "Parsing error: Unexpected token is",
508508
line: 1,
509-
column: 19
509+
column: 19,
510+
nodeType: null
510511
}
511512
],
512513
suppressedMessages: [],
@@ -546,7 +547,8 @@ describe("FlatESLint", () => {
546547
severity: 2,
547548
message: "Parsing error: Unexpected token",
548549
line: 1,
549-
column: 10
550+
column: 10,
551+
nodeType: null
550552
}
551553
],
552554
suppressedMessages: [],
@@ -636,7 +638,8 @@ describe("FlatESLint", () => {
636638
severity: 2,
637639
message: "Parsing error: Unexpected token is",
638640
line: 1,
639-
column: 19
641+
column: 19,
642+
nodeType: null
640643
}
641644
],
642645
suppressedMessages: [],
@@ -5088,9 +5091,11 @@ describe("FlatESLint", () => {
50885091
fixableWarningCount: 0,
50895092
messages: [
50905093
{
5094+
ruleId: null,
50915095
fatal: false,
50925096
message: "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.",
5093-
severity: 1
5097+
severity: 1,
5098+
nodeType: null
50945099
}
50955100
],
50965101
usedDeprecatedRules: [],

0 commit comments

Comments
 (0)