Skip to content

Commit 01d0eef

Browse files
authored
fix: false positive with no-unused-message-ids from external violation reporting function (#286)
1 parent 3657287 commit 01d0eef

File tree

2 files changed

+42
-37
lines changed

2 files changed

+42
-37
lines changed

Diff for: lib/rules/no-unused-message-ids.js

+33-19
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ module.exports = {
3030

3131
const messageIdsUsed = new Set();
3232
let contextIdentifiers;
33-
let shouldPerformUnusedCheck = true;
33+
let hasSeenUnknownMessageId = false;
34+
let hasSeenViolationReport = false;
3435

3536
const messageIdNodes = utils.getMessageIdNodes(info, scopeManager);
3637
if (!messageIdNodes) {
@@ -44,22 +45,29 @@ module.exports = {
4445
},
4546

4647
'Program:exit'() {
47-
if (shouldPerformUnusedCheck) {
48-
const messageIdNodesUnused = messageIdNodes.filter(
49-
(node) =>
50-
!messageIdsUsed.has(utils.getKeyName(node, context.getScope()))
51-
);
52-
53-
// Report any messageIds that were never used.
54-
for (const messageIdNode of messageIdNodesUnused) {
55-
context.report({
56-
node: messageIdNode,
57-
messageId: 'unusedMessage',
58-
data: {
59-
messageId: utils.getKeyName(messageIdNode, context.getScope()),
60-
},
61-
});
62-
}
48+
if (hasSeenUnknownMessageId || !hasSeenViolationReport) {
49+
/*
50+
Bail out when the rule is likely to have false positives.
51+
- If we saw a dynamic/unknown messageId
52+
- If we couldn't find any violation reporting code, likely because a helper function from an external file is handling this
53+
*/
54+
return;
55+
}
56+
57+
const messageIdNodesUnused = messageIdNodes.filter(
58+
(node) =>
59+
!messageIdsUsed.has(utils.getKeyName(node, context.getScope()))
60+
);
61+
62+
// Report any messageIds that were never used.
63+
for (const messageIdNode of messageIdNodesUnused) {
64+
context.report({
65+
node: messageIdNode,
66+
messageId: 'unusedMessage',
67+
data: {
68+
messageId: utils.getKeyName(messageIdNode, context.getScope()),
69+
},
70+
});
6371
}
6472
},
6573

@@ -76,6 +84,8 @@ module.exports = {
7684
return;
7785
}
7886

87+
hasSeenViolationReport = true;
88+
7989
const reportMessagesAndDataArray =
8090
utils.collectReportViolationAndSuggestionData(reportInfo);
8191
for (const { messageId } of reportMessagesAndDataArray.filter(
@@ -90,7 +100,7 @@ module.exports = {
90100
values.some((val) => val.type !== 'Literal')
91101
) {
92102
// When a dynamic messageId is used and we can't detect its value, disable the rule to avoid false positives.
93-
shouldPerformUnusedCheck = false;
103+
hasSeenUnknownMessageId = true;
94104
}
95105
values.forEach((val) => messageIdsUsed.add(val.value));
96106
}
@@ -101,17 +111,21 @@ module.exports = {
101111
// In order to reduce false positives, we will also check for messageId properties anywhere in the file.
102112
// This is helpful especially in the event that helper functions are used for reporting violations.
103113
if (node.key.type === 'Identifier' && node.key.name === 'messageId') {
114+
hasSeenViolationReport = true;
115+
104116
const values =
105117
node.value.type === 'Literal'
106118
? [node.value]
107119
: utils.findPossibleVariableValues(node.value, scopeManager);
120+
108121
if (
109122
values.length === 0 ||
110123
values.some((val) => val.type !== 'Literal')
111124
) {
112125
// When a dynamic messageId is used and we can't detect its value, disable the rule to avoid false positives.
113-
shouldPerformUnusedCheck = false;
126+
hasSeenUnknownMessageId = true;
114127
}
128+
115129
values.forEach((val) => messageIdsUsed.add(val.value));
116130
}
117131
},

Diff for: tests/lib/rules/no-unused-message-ids.js

+9-18
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ ruleTester.run('no-unused-message-ids', rule, {
220220
}
221221
};
222222
`,
223+
// Ignore when we couldn't find any calls to `context.report()`, likely because an external helper function is in use.
224+
`
225+
module.exports = {
226+
meta: { messages: { foo: 'bar' } },
227+
create(context) {}
228+
};
229+
`,
223230
],
224231

225232
invalid: [
@@ -313,29 +320,13 @@ ruleTester.run('no-unused-message-ids', rule, {
313320
},
314321
],
315322
},
316-
{
317-
// messageId unused with no reports
318-
code: `
319-
module.exports = {
320-
meta: { messages: { foo: 'hello world' } },
321-
create(context) { }
322-
};
323-
`,
324-
errors: [
325-
{
326-
messageId: 'unusedMessage',
327-
data: { messageId: 'foo' },
328-
type: 'Property',
329-
},
330-
],
331-
},
332323
{
333324
// messageId unused with meta.messages in variable
334325
code: `
335326
const messages = { foo: 'hello world' };
336327
module.exports = {
337328
meta: { messages },
338-
create(context) { }
329+
create(context) { context.report({node, messageId: 'other'}); }
339330
};
340331
`,
341332
errors: [
@@ -353,7 +344,7 @@ ruleTester.run('no-unused-message-ids', rule, {
353344
const extraMeta = { messages: { ...extraMessages } };
354345
module.exports = {
355346
meta: { ...extraMeta },
356-
create(context) { }
347+
create(context) { context.report({node, messageId: 'other'}); }
357348
};
358349
`,
359350
errors: [

0 commit comments

Comments
 (0)