forked from eslint-community/eslint-plugin-eslint-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrequire-meta-docs-url.js
133 lines (116 loc) · 4.22 KB
/
require-meta-docs-url.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* @author Toru Nagashima <https://github.com/mysticatea>
*/
'use strict';
// -----------------------------------------------------------------------------
// Requirements
// -----------------------------------------------------------------------------
const path = require('path');
const util = require('../utils');
const { getStaticValue } = require('eslint-utils');
// -----------------------------------------------------------------------------
// Rule Definition
// -----------------------------------------------------------------------------
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'require rules to implement a `meta.docs.url` property',
category: 'Rules',
recommended: false,
},
fixable: 'code',
schema: [{
type: 'object',
properties: {
pattern: { type: 'string' },
},
additionalProperties: false,
}],
messages: {
mismatch: '`meta.docs.url` property must be `{{expectedUrl}}`.',
missing: 'Rules should export a `meta.docs.url` property.',
wrongType: '`meta.docs.url` property must be a string.',
},
},
/**
* Creates AST event handlers for require-meta-docs-url.
* @param {RuleContext} context - The rule context.
* @returns {Object} AST event handlers.
*/
create (context) {
const options = context.options[0] || {};
const sourceCode = context.getSourceCode();
const filename = context.getFilename();
const ruleName = filename === '<input>' ? undefined : path.basename(filename, '.js');
const expectedUrl = !options.pattern || !ruleName
? undefined
: options.pattern.replace(/{{\s*name\s*}}/g, ruleName);
/**
* Check whether a given URL is the expected URL.
* @param {string} url The URL to check.
* @returns {boolean} `true` if the node is the expected URL.
*/
function isExpectedUrl (url) {
return Boolean(
typeof url === 'string' &&
(
expectedUrl === undefined ||
url === expectedUrl
)
);
}
return {
Program () {
const info = util.getRuleInfo(sourceCode);
if (info === null) {
return;
}
const metaNode = info.meta;
const docsPropNode =
metaNode &&
metaNode.properties &&
metaNode.properties.find(p => p.type === 'Property' && util.getKeyName(p) === 'docs');
const urlPropNode =
docsPropNode &&
docsPropNode.value.properties &&
docsPropNode.value.properties.find(p => p.type === 'Property' && util.getKeyName(p) === 'url');
const staticValue = urlPropNode ? getStaticValue(urlPropNode.value, context.getScope()) : undefined;
if (urlPropNode && !staticValue) {
// Ignore non-static values since we can't determine what they look like.
return;
}
if (isExpectedUrl(staticValue && staticValue.value)) {
return;
}
context.report({
node: (urlPropNode && urlPropNode.value) || (docsPropNode && docsPropNode.value) || metaNode || info.create,
messageId:
!urlPropNode ? 'missing' :
// eslint-disable-next-line unicorn/no-nested-ternary
!expectedUrl ? 'wrongType' :
/* otherwise */ 'mismatch',
data: {
expectedUrl,
},
fix (fixer) {
if (!expectedUrl) {
return null;
}
const urlString = JSON.stringify(expectedUrl);
if (urlPropNode) {
if (urlPropNode.value.type === 'Literal' || (urlPropNode.value.type === 'Identifier' && urlPropNode.value.name === 'undefined')) {
return fixer.replaceText(urlPropNode.value, urlString);
}
} else if (docsPropNode && docsPropNode.value.type === 'ObjectExpression') {
return util.insertProperty(fixer, docsPropNode.value, `url: ${urlString}`, sourceCode);
} else if (!docsPropNode && metaNode && metaNode.type === 'ObjectExpression') {
return util.insertProperty(fixer, metaNode, `docs: {\nurl: ${urlString}\n}`, sourceCode);
}
return null;
},
});
},
};
},
};