-
-
Notifications
You must be signed in to change notification settings - Fork 681
/
Copy pathno-invalid-meta.js
127 lines (110 loc) · 3.56 KB
/
no-invalid-meta.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
/**
* @fileoverview Internal rule to prevent missing or invalid meta property in core rules.
* @author Vitor Balocco
*/
'use strict'
// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------
/**
* Gets the property of the Object node passed in that has the name specified.
*
* @param {string} property Name of the property to return.
* @param {ASTNode} node The ObjectExpression node.
* @returns {ASTNode} The Property node or null if not found.
*/
function getPropertyFromObject(property, node) {
if (node && node.type === 'ObjectExpression') {
for (const prop of node.properties) {
if (prop.type === 'Property' && prop.key.name === property) {
return prop
}
}
}
return null
}
/**
* Extracts the `meta` property from the ObjectExpression that all rules export.
*
* @param {ASTNode} exportsNode ObjectExpression node that the rule exports.
* @returns {ASTNode} The `meta` Property node or null if not found.
*/
function getMetaPropertyFromExportsNode(exportsNode) {
return getPropertyFromObject('meta', exportsNode)
}
/**
* Whether this `meta` ObjectExpression has a `docs` property defined or not.
*
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
* @returns {boolean} `true` if a `docs` property exists.
*/
function hasMetaDocs(metaPropertyNode) {
return Boolean(getPropertyFromObject('docs', metaPropertyNode.value))
}
/**
* Whether this `meta` ObjectExpression has a `docs.category` property defined or not.
*
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
* @returns {boolean} `true` if a `docs.category` property exists.
*/
function hasMetaDocsCategories(metaPropertyNode) {
const metaDocs = getPropertyFromObject('docs', metaPropertyNode.value)
return metaDocs && getPropertyFromObject('categories', metaDocs.value)
}
/**
* Checks the validity of the meta definition of this rule and reports any errors found.
*
* @param {RuleContext} context The ESLint rule context.
* @param {ASTNode} exportsNode ObjectExpression node that the rule exports.
* @param {boolean} ruleIsFixable whether the rule is fixable or not.
* @returns {void}
*/
function checkMetaValidity(context, exportsNode) {
const metaProperty = getMetaPropertyFromExportsNode(exportsNode)
if (!metaProperty) {
context.report(exportsNode, 'Rule is missing a meta property.')
return
}
if (!hasMetaDocs(metaProperty)) {
context.report(metaProperty, 'Rule is missing a meta.docs property.')
return
}
if (!hasMetaDocsCategories(metaProperty)) {
context.report(
metaProperty,
'Rule is missing a meta.docs.categories property.'
)
return
}
}
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: 'enforce correct use of `meta` property in core rules',
categories: ['Internal']
},
schema: []
},
create(context) {
let exportsNode
return {
AssignmentExpression(node) {
if (
node.left &&
node.right &&
node.left.type === 'MemberExpression' &&
node.left.object.name === 'module' &&
node.left.property.name === 'exports'
) {
exportsNode = node.right
}
},
'Program:exit'(programNode) {
checkMetaValidity(context, exportsNode)
}
}
}
}