Skip to content

Commit

Permalink
handle variable messages object keys in no-{missing,unused}-message-i…
Browse files Browse the repository at this point in the history
…ds and add messageId to messages
  • Loading branch information
bmish committed Jul 1, 2022
1 parent da64dc0 commit 68b7e43
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 44 deletions.
13 changes: 11 additions & 2 deletions lib/rules/no-missing-message-ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ module.exports = {
fixable: null,
schema: [],
messages: {
missingMessage: '`meta.messages` is missing this `messageId`.',
missingMessage:
'`meta.messages` is missing the messageId "{{messageId}}".',
},
},

Expand Down Expand Up @@ -72,12 +73,20 @@ module.exports = {
val.type === 'Literal' &&
val.value !== null &&
val.value !== '' &&
!utils.getMessageIdNodeById(val.value, ruleInfo, scopeManager)
!utils.getMessageIdNodeById(
val.value,
ruleInfo,
scopeManager,
context.getScope()
)
)
// Couldn't find this messageId in `meta.messages`.
context.report({
node: val,
messageId: 'missingMessage',
data: {
messageId: val.value,
},
});
});
}
Expand Down
15 changes: 11 additions & 4 deletions lib/rules/no-unused-message-ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module.exports = {
fixable: null,
schema: [],
messages: {
unusedMessage: 'This message is never used.',
unusedMessage: 'The messageId "{{messageId}}" is never used.',
},
},

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

'Program:exit'() {
if (shouldPerformUnusedCheck) {
for (const messageIdNode of messageIdNodes.filter(
(node) => !messageIdsUsed.has(node.key.name)
)) {
const messageIdNodesUnused = messageIdNodes.filter(
(node) =>
!messageIdsUsed.has(utils.getKeyName(node, context.getScope()))
);

// Report any messageIds that were never used.
for (const messageIdNode of messageIdNodesUnused) {
context.report({
node: messageIdNode,
messageId: 'unusedMessage',
data: {
messageId: utils.getKeyName(messageIdNode, context.getScope()),
},
});
}
}
Expand Down
19 changes: 15 additions & 4 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,24 @@ module.exports = {
/**
* Gets the key name of a Property, if it can be determined statically.
* @param {ASTNode} node The `Property` node
* @param {Scope} scope
* @returns {string|null} The key name, or `null` if the name cannot be determined statically.
*/
getKeyName(property) {
getKeyName(property, scope) {
if (!property.key) {
// likely a SpreadElement or another non-standard node
return null;
}
if (!property.computed && property.key.type === 'Identifier') {
if (property.key.type === 'Identifier') {
if (property.computed) {
// Variable key: { [myVariable]: 'hello world' }
if (scope) {
const staticValue = getStaticValue(property.key, scope);
return staticValue ? staticValue.value : null;
}
// TODO: ensure scope is always passed to getKeyName() so we don't need to handle the case where it's not passed.
return null;
}
return property.key.name;
}
if (property.key.type === 'Literal') {
Expand Down Expand Up @@ -838,12 +848,13 @@ module.exports = {
* @param {ScopeManager} scopeManager
* @returns {Node|undefined} The matching messageId property from `meta.messages`.
*/
getMessageIdNodeById(messageId, ruleInfo, scopeManager) {
getMessageIdNodeById(messageId, ruleInfo, scopeManager, scope) {
return module.exports
.getMessageIdNodes(ruleInfo, scopeManager)
.find(
(p) =>
p.type === 'Property' && module.exports.getKeyName(p) === messageId
p.type === 'Property' &&
module.exports.getKeyName(p, scope) === messageId
);
},

Expand Down
61 changes: 52 additions & 9 deletions tests/lib/rules/no-missing-message-ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ ruleTester.run('no-missing-message-ids', rule, {
}
};
`,
// with variable messageId key
`
const MESSAGE_ID = 'foo';
const messages = {
[MESSAGE_ID]: 'hello world',
};
module.exports = {
meta: { messages },
create(context) {
context.report({node, messageId: MESSAGE_ID});
}
};
`,
],

invalid: [
Expand All @@ -192,11 +205,17 @@ ruleTester.run('no-missing-message-ids', rule, {
module.exports = {
meta: { messages: { } },
create(context) {
context.report({ node, messageId: 'bar' });
context.report({ node, messageId: 'foo' });
}
};
`,
errors: [{ messageId: 'missingMessage', type: 'Literal' }],
errors: [
{
messageId: 'missingMessage',
data: { messageId: 'foo' },
type: 'Literal',
},
],
},
{
// Missing messages with multiple possible values
Expand All @@ -212,9 +231,21 @@ ruleTester.run('no-missing-message-ids', rule, {
};
`,
errors: [
{ messageId: 'missingMessage', type: 'Literal' },
{ messageId: 'missingMessage', type: 'Literal' },
{ messageId: 'missingMessage', type: 'Literal' },
{
messageId: 'missingMessage',
data: { messageId: 'abc' },
type: 'Literal',
},
{
messageId: 'missingMessage',
data: { messageId: 'def' },
type: 'Literal',
},
{
messageId: 'missingMessage',
data: { messageId: 'bar' },
type: 'Literal',
},
],
},
{
Expand All @@ -225,24 +256,36 @@ ruleTester.run('no-missing-message-ids', rule, {
module.exports = {
meta: { ...extraMeta },
create(context) {
context.report({ node, messageId: 'bar' });
context.report({ node, messageId: 'foo' });
}
};
`,
errors: [{ messageId: 'missingMessage', type: 'Literal' }],
errors: [
{
messageId: 'missingMessage',
data: { messageId: 'foo' },
type: 'Literal',
},
],
},
{
// ESM
code: `
export default {
meta: { messages: { } },
create(context) {
context.report({ node, messageId: 'bar' });
context.report({ node, messageId: 'foo' });
}
};
`,
parserOptions: { sourceType: 'module' },
errors: [{ messageId: 'missingMessage', type: 'Literal' }],
errors: [
{
messageId: 'missingMessage',
data: { messageId: 'foo' },
type: 'Literal',
},
],
},
],
});
89 changes: 78 additions & 11 deletions tests/lib/rules/no-unused-message-ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,19 @@ ruleTester.run('no-unused-message-ids', rule, {
}
};
`,
// with variable messageId key
`
const MESSAGE_ID = 'foo';
const messages = {
[MESSAGE_ID]: 'hello world',
};
module.exports = {
meta: { messages },
create(context) {
context.report({node, messageId: MESSAGE_ID});
}
};
`,
],

invalid: [
Expand All @@ -220,7 +233,13 @@ ruleTester.run('no-unused-message-ids', rule, {
}
};
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// Unused message with spreads
Expand All @@ -234,7 +253,13 @@ ruleTester.run('no-unused-message-ids', rule, {
}
};
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// ESM
Expand All @@ -247,7 +272,13 @@ ruleTester.run('no-unused-message-ids', rule, {
};
`,
parserOptions: { sourceType: 'module' },
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// `meta` / `create` in variables
Expand All @@ -256,19 +287,31 @@ ruleTester.run('no-unused-message-ids', rule, {
const create = function (context) { context.report({ node, messageId: 'bar' }); }
module.exports = { meta, create };
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// messageId unused
// messageId unused with multiple messages
code: `
module.exports = {
meta: { messages: { foo: 'hello world', bar: 'hello world 2' } },
create(context) {
context.report({ node, messageId: 'foo' });
context.report({ node, messageId: 'bar' });
}
};
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// messageId unused with no reports
Expand All @@ -278,7 +321,13 @@ ruleTester.run('no-unused-message-ids', rule, {
create(context) { }
};
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// messageId unused with meta.messages in variable
Expand All @@ -289,7 +338,13 @@ ruleTester.run('no-unused-message-ids', rule, {
create(context) { }
};
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// messageId unused with meta.messages in spreads
Expand All @@ -301,7 +356,13 @@ ruleTester.run('no-unused-message-ids', rule, {
create(context) { }
};
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
{
// helper function outside rule with variable messageId
Expand All @@ -317,7 +378,13 @@ ruleTester.run('no-unused-message-ids', rule, {
}
};
`,
errors: [{ messageId: 'unusedMessage', type: 'Property' }],
errors: [
{
messageId: 'unusedMessage',
data: { messageId: 'foo' },
type: 'Property',
},
],
},
],
});
Loading

0 comments on commit 68b7e43

Please sign in to comment.