Skip to content

Commit 3a9825f

Browse files
committed
handle variable messages object keys in no-{missing,unused}-message-ids and add messageId to messages
1 parent da64dc0 commit 3a9825f

File tree

6 files changed

+230
-46
lines changed

6 files changed

+230
-46
lines changed

lib/rules/no-missing-message-ids.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ module.exports = {
2020
fixable: null,
2121
schema: [],
2222
messages: {
23-
missingMessage: '`meta.messages` is missing this `messageId`.',
23+
missingMessage:
24+
'`meta.messages` is missing the messageId "{{messageId}}".',
2425
},
2526
},
2627

@@ -72,12 +73,20 @@ module.exports = {
7273
val.type === 'Literal' &&
7374
val.value !== null &&
7475
val.value !== '' &&
75-
!utils.getMessageIdNodeById(val.value, ruleInfo, scopeManager)
76+
!utils.getMessageIdNodeById(
77+
val.value,
78+
ruleInfo,
79+
scopeManager,
80+
context.getScope()
81+
)
7682
)
7783
// Couldn't find this messageId in `meta.messages`.
7884
context.report({
7985
node: val,
8086
messageId: 'missingMessage',
87+
data: {
88+
messageId: val.value,
89+
},
8190
});
8291
});
8392
}

lib/rules/no-unused-message-ids.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module.exports = {
1919
fixable: null,
2020
schema: [],
2121
messages: {
22-
unusedMessage: 'This message is never used.',
22+
unusedMessage: 'The messageId "{{messageId}}" is never used.',
2323
},
2424
},
2525

@@ -45,12 +45,19 @@ module.exports = {
4545

4646
'Program:exit'() {
4747
if (shouldPerformUnusedCheck) {
48-
for (const messageIdNode of messageIdNodes.filter(
49-
(node) => !messageIdsUsed.has(node.key.name)
50-
)) {
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) {
5155
context.report({
5256
node: messageIdNode,
5357
messageId: 'unusedMessage',
58+
data: {
59+
messageId: utils.getKeyName(messageIdNode, context.getScope()),
60+
},
5461
});
5562
}
5663
}

lib/utils.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -378,14 +378,24 @@ module.exports = {
378378
/**
379379
* Gets the key name of a Property, if it can be determined statically.
380380
* @param {ASTNode} node The `Property` node
381+
* @param {Scope} scope
381382
* @returns {string|null} The key name, or `null` if the name cannot be determined statically.
382383
*/
383-
getKeyName(property) {
384+
getKeyName(property, scope) {
384385
if (!property.key) {
385386
// likely a SpreadElement or another non-standard node
386387
return null;
387388
}
388-
if (!property.computed && property.key.type === 'Identifier') {
389+
if (property.key.type === 'Identifier') {
390+
if (property.computed) {
391+
// Variable key: { [myVariable]: 'hello world' }
392+
if (scope) {
393+
const staticValue = getStaticValue(property.key, scope);
394+
return staticValue ? staticValue.value : null;
395+
}
396+
// TODO: ensure scope is always passed to getKeyName() so we don't need to handle the case where it's not passed.
397+
return null;
398+
}
389399
return property.key.name;
390400
}
391401
if (property.key.type === 'Literal') {
@@ -836,14 +846,16 @@ module.exports = {
836846
* @param {String} messageId - the messageId to check for
837847
* @param {RuleInfo} ruleInfo
838848
* @param {ScopeManager} scopeManager
849+
* @param {Scope} scope
839850
* @returns {Node|undefined} The matching messageId property from `meta.messages`.
840851
*/
841-
getMessageIdNodeById(messageId, ruleInfo, scopeManager) {
852+
getMessageIdNodeById(messageId, ruleInfo, scopeManager, scope) {
842853
return module.exports
843854
.getMessageIdNodes(ruleInfo, scopeManager)
844855
.find(
845856
(p) =>
846-
p.type === 'Property' && module.exports.getKeyName(p) === messageId
857+
p.type === 'Property' &&
858+
module.exports.getKeyName(p, scope) === messageId
847859
);
848860
},
849861

tests/lib/rules/no-missing-message-ids.js

+52-9
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ ruleTester.run('no-missing-message-ids', rule, {
183183
}
184184
};
185185
`,
186+
// with variable messageId key
187+
`
188+
const MESSAGE_ID = 'foo';
189+
const messages = {
190+
[MESSAGE_ID]: 'hello world',
191+
};
192+
module.exports = {
193+
meta: { messages },
194+
create(context) {
195+
context.report({node, messageId: MESSAGE_ID});
196+
}
197+
};
198+
`,
186199
],
187200

188201
invalid: [
@@ -192,11 +205,17 @@ ruleTester.run('no-missing-message-ids', rule, {
192205
module.exports = {
193206
meta: { messages: { } },
194207
create(context) {
195-
context.report({ node, messageId: 'bar' });
208+
context.report({ node, messageId: 'foo' });
196209
}
197210
};
198211
`,
199-
errors: [{ messageId: 'missingMessage', type: 'Literal' }],
212+
errors: [
213+
{
214+
messageId: 'missingMessage',
215+
data: { messageId: 'foo' },
216+
type: 'Literal',
217+
},
218+
],
200219
},
201220
{
202221
// Missing messages with multiple possible values
@@ -212,9 +231,21 @@ ruleTester.run('no-missing-message-ids', rule, {
212231
};
213232
`,
214233
errors: [
215-
{ messageId: 'missingMessage', type: 'Literal' },
216-
{ messageId: 'missingMessage', type: 'Literal' },
217-
{ messageId: 'missingMessage', type: 'Literal' },
234+
{
235+
messageId: 'missingMessage',
236+
data: { messageId: 'abc' },
237+
type: 'Literal',
238+
},
239+
{
240+
messageId: 'missingMessage',
241+
data: { messageId: 'def' },
242+
type: 'Literal',
243+
},
244+
{
245+
messageId: 'missingMessage',
246+
data: { messageId: 'bar' },
247+
type: 'Literal',
248+
},
218249
],
219250
},
220251
{
@@ -225,24 +256,36 @@ ruleTester.run('no-missing-message-ids', rule, {
225256
module.exports = {
226257
meta: { ...extraMeta },
227258
create(context) {
228-
context.report({ node, messageId: 'bar' });
259+
context.report({ node, messageId: 'foo' });
229260
}
230261
};
231262
`,
232-
errors: [{ messageId: 'missingMessage', type: 'Literal' }],
263+
errors: [
264+
{
265+
messageId: 'missingMessage',
266+
data: { messageId: 'foo' },
267+
type: 'Literal',
268+
},
269+
],
233270
},
234271
{
235272
// ESM
236273
code: `
237274
export default {
238275
meta: { messages: { } },
239276
create(context) {
240-
context.report({ node, messageId: 'bar' });
277+
context.report({ node, messageId: 'foo' });
241278
}
242279
};
243280
`,
244281
parserOptions: { sourceType: 'module' },
245-
errors: [{ messageId: 'missingMessage', type: 'Literal' }],
282+
errors: [
283+
{
284+
messageId: 'missingMessage',
285+
data: { messageId: 'foo' },
286+
type: 'Literal',
287+
},
288+
],
246289
},
247290
],
248291
});

tests/lib/rules/no-unused-message-ids.js

+78-11
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,19 @@ ruleTester.run('no-unused-message-ids', rule, {
207207
}
208208
};
209209
`,
210+
// with variable messageId key
211+
`
212+
const MESSAGE_ID = 'foo';
213+
const messages = {
214+
[MESSAGE_ID]: 'hello world',
215+
};
216+
module.exports = {
217+
meta: { messages },
218+
create(context) {
219+
context.report({node, messageId: MESSAGE_ID});
220+
}
221+
};
222+
`,
210223
],
211224

212225
invalid: [
@@ -220,7 +233,13 @@ ruleTester.run('no-unused-message-ids', rule, {
220233
}
221234
};
222235
`,
223-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
236+
errors: [
237+
{
238+
messageId: 'unusedMessage',
239+
data: { messageId: 'foo' },
240+
type: 'Property',
241+
},
242+
],
224243
},
225244
{
226245
// Unused message with spreads
@@ -234,7 +253,13 @@ ruleTester.run('no-unused-message-ids', rule, {
234253
}
235254
};
236255
`,
237-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
256+
errors: [
257+
{
258+
messageId: 'unusedMessage',
259+
data: { messageId: 'foo' },
260+
type: 'Property',
261+
},
262+
],
238263
},
239264
{
240265
// ESM
@@ -247,7 +272,13 @@ ruleTester.run('no-unused-message-ids', rule, {
247272
};
248273
`,
249274
parserOptions: { sourceType: 'module' },
250-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
275+
errors: [
276+
{
277+
messageId: 'unusedMessage',
278+
data: { messageId: 'foo' },
279+
type: 'Property',
280+
},
281+
],
251282
},
252283
{
253284
// `meta` / `create` in variables
@@ -256,19 +287,31 @@ ruleTester.run('no-unused-message-ids', rule, {
256287
const create = function (context) { context.report({ node, messageId: 'bar' }); }
257288
module.exports = { meta, create };
258289
`,
259-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
290+
errors: [
291+
{
292+
messageId: 'unusedMessage',
293+
data: { messageId: 'foo' },
294+
type: 'Property',
295+
},
296+
],
260297
},
261298
{
262-
// messageId unused
299+
// messageId unused with multiple messages
263300
code: `
264301
module.exports = {
265302
meta: { messages: { foo: 'hello world', bar: 'hello world 2' } },
266303
create(context) {
267-
context.report({ node, messageId: 'foo' });
304+
context.report({ node, messageId: 'bar' });
268305
}
269306
};
270307
`,
271-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
308+
errors: [
309+
{
310+
messageId: 'unusedMessage',
311+
data: { messageId: 'foo' },
312+
type: 'Property',
313+
},
314+
],
272315
},
273316
{
274317
// messageId unused with no reports
@@ -278,7 +321,13 @@ ruleTester.run('no-unused-message-ids', rule, {
278321
create(context) { }
279322
};
280323
`,
281-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
324+
errors: [
325+
{
326+
messageId: 'unusedMessage',
327+
data: { messageId: 'foo' },
328+
type: 'Property',
329+
},
330+
],
282331
},
283332
{
284333
// messageId unused with meta.messages in variable
@@ -289,7 +338,13 @@ ruleTester.run('no-unused-message-ids', rule, {
289338
create(context) { }
290339
};
291340
`,
292-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
341+
errors: [
342+
{
343+
messageId: 'unusedMessage',
344+
data: { messageId: 'foo' },
345+
type: 'Property',
346+
},
347+
],
293348
},
294349
{
295350
// messageId unused with meta.messages in spreads
@@ -301,7 +356,13 @@ ruleTester.run('no-unused-message-ids', rule, {
301356
create(context) { }
302357
};
303358
`,
304-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
359+
errors: [
360+
{
361+
messageId: 'unusedMessage',
362+
data: { messageId: 'foo' },
363+
type: 'Property',
364+
},
365+
],
305366
},
306367
{
307368
// helper function outside rule with variable messageId
@@ -317,7 +378,13 @@ ruleTester.run('no-unused-message-ids', rule, {
317378
}
318379
};
319380
`,
320-
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
381+
errors: [
382+
{
383+
messageId: 'unusedMessage',
384+
data: { messageId: 'foo' },
385+
type: 'Property',
386+
},
387+
],
321388
},
322389
],
323390
});

0 commit comments

Comments
 (0)