Skip to content

Commit aad2c10

Browse files
committed
Fix: Improve detection of static url strings in require-meta-docs-url rule
* Add static value detection for `url` variables * Ignore when we can't statically determine the value of a given `url` * Improve reporting location and tests for this * Use `messageId` * Add tests
1 parent c10afb8 commit aad2c10

File tree

2 files changed

+172
-65
lines changed

2 files changed

+172
-65
lines changed

lib/rules/require-meta-docs-url.js

+37-28
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
const path = require('path');
1212
const util = require('../utils');
13+
const { getStaticValue } = require('eslint-utils');
1314

1415
// -----------------------------------------------------------------------------
1516
// Rule Definition
@@ -31,6 +32,11 @@ module.exports = {
3132
},
3233
additionalProperties: false,
3334
}],
35+
messages: {
36+
mismatch: '`meta.docs.url` property must be `{{expectedUrl}}`.',
37+
missing: 'Rules should export a `meta.docs.url` property.',
38+
wrongType: '`meta.docs.url` property must be a string.',
39+
},
3440
},
3541

3642
/**
@@ -48,24 +54,22 @@ module.exports = {
4854
: options.pattern.replace(/{{\s*name\s*}}/g, ruleName);
4955

5056
/**
51-
* Check whether a given node is the expected URL.
52-
* @param {Node} node The node of property value to check.
57+
* Check whether a given URL is the expected URL.
58+
* @param {String} url The URL to check.
5359
* @returns {boolean} `true` if the node is the expected URL.
5460
*/
55-
function isExpectedUrl (node) {
61+
function isExpectedUrl (url) {
5662
return Boolean(
57-
node &&
58-
node.type === 'Literal' &&
59-
typeof node.value === 'string' &&
63+
typeof url === 'string' &&
6064
(
6165
expectedUrl === undefined ||
62-
node.value === expectedUrl
66+
url === expectedUrl
6367
)
6468
);
6569
}
6670

6771
return {
68-
Program (node) {
72+
Program () {
6973
const info = util.getRuleInfo(sourceCode);
7074
if (info === null) {
7175
return;
@@ -81,40 +85,45 @@ module.exports = {
8185
docsPropNode.value.properties &&
8286
docsPropNode.value.properties.find(p => p.type === 'Property' && util.getKeyName(p) === 'url');
8387

84-
if (isExpectedUrl(urlPropNode && urlPropNode.value)) {
88+
const staticValue = urlPropNode ? getStaticValue(urlPropNode.value, context.getScope()) : undefined;
89+
if (urlPropNode && !staticValue) {
90+
// Ignore non-static values since we can't determine what they look like.
91+
return;
92+
}
93+
94+
if (isExpectedUrl(staticValue && staticValue.value)) {
8595
return;
8696
}
8797

8898
context.report({
89-
loc:
90-
(urlPropNode && urlPropNode.value.loc) ||
91-
(docsPropNode && docsPropNode.value.loc) ||
92-
(metaNode && metaNode.loc) ||
93-
node.loc.start,
94-
95-
message:
96-
!urlPropNode ? 'Rules should export a `meta.docs.url` property.' :
99+
node: (urlPropNode && urlPropNode.value) || (docsPropNode && docsPropNode.value) || metaNode || info.create,
100+
101+
messageId:
102+
!urlPropNode ? 'missing' :
97103
// eslint-disable-next-line unicorn/no-nested-ternary
98-
!expectedUrl ? '`meta.docs.url` property must be a string.' :
99-
/* otherwise */ '`meta.docs.url` property must be `{{expectedUrl}}`.',
104+
!expectedUrl ? 'wrongType' :
105+
/* otherwise */ 'mismatch',
100106

101107
data: {
102108
expectedUrl,
103109
},
104110

105111
fix (fixer) {
106-
if (expectedUrl) {
107-
const urlString = JSON.stringify(expectedUrl);
108-
if (urlPropNode) {
112+
if (!expectedUrl) {
113+
return null;
114+
}
115+
116+
const urlString = JSON.stringify(expectedUrl);
117+
if (urlPropNode) {
118+
if (urlPropNode.value.type === 'Literal') {
109119
return fixer.replaceText(urlPropNode.value, urlString);
110120
}
111-
if (docsPropNode && docsPropNode.value.type === 'ObjectExpression') {
112-
return util.insertProperty(fixer, docsPropNode.value, `url: ${urlString}`, sourceCode);
113-
}
114-
if (!docsPropNode && metaNode && metaNode.type === 'ObjectExpression') {
115-
return util.insertProperty(fixer, metaNode, `docs: {\nurl: ${urlString}\n}`, sourceCode);
116-
}
121+
} else if (docsPropNode && docsPropNode.value.type === 'ObjectExpression') {
122+
return util.insertProperty(fixer, docsPropNode.value, `url: ${urlString}`, sourceCode);
123+
} else if (!docsPropNode && metaNode && metaNode.type === 'ObjectExpression') {
124+
return util.insertProperty(fixer, metaNode, `docs: {\nurl: ${urlString}\n}`, sourceCode);
117125
}
126+
118127
return null;
119128
},
120129
});

0 commit comments

Comments
 (0)