]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
1 | /** |
2 | * @fileoverview Internal rule to prevent missing or invalid meta property in core rules. | |
3 | * @author Vitor Balocco | |
4 | */ | |
5 | ||
6 | "use strict"; | |
7 | ||
8 | //------------------------------------------------------------------------------ | |
9 | // Helpers | |
10 | //------------------------------------------------------------------------------ | |
11 | ||
12 | /** | |
13 | * Gets the property of the Object node passed in that has the name specified. | |
14 | * @param {string} property Name of the property to return. | |
15 | * @param {ASTNode} node The ObjectExpression node. | |
16 | * @returns {ASTNode} The Property node or null if not found. | |
17 | */ | |
18 | function getPropertyFromObject(property, node) { | |
19 | const properties = node.properties; | |
20 | ||
21 | if (!Array.isArray(properties)) { | |
22 | ||
23 | return null; | |
24 | } | |
25 | ||
26 | for (let i = 0; i < properties.length; i++) { | |
27 | if (properties[i].key.name === property) { | |
28 | return properties[i]; | |
29 | } | |
30 | } | |
31 | ||
32 | return null; | |
33 | } | |
34 | ||
35 | /** | |
36 | * Extracts the `meta` property from the ObjectExpression that all rules export. | |
37 | * @param {ASTNode} exportsNode ObjectExpression node that the rule exports. | |
38 | * @returns {ASTNode} The `meta` Property node or null if not found. | |
39 | */ | |
40 | function getMetaPropertyFromExportsNode(exportsNode) { | |
41 | return getPropertyFromObject("meta", exportsNode); | |
42 | } | |
43 | ||
44 | /** | |
45 | * Whether this `meta` ObjectExpression has a `docs` property defined or not. | |
46 | * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. | |
47 | * @returns {boolean} `true` if a `docs` property exists. | |
48 | */ | |
49 | function hasMetaDocs(metaPropertyNode) { | |
50 | return Boolean(getPropertyFromObject("docs", metaPropertyNode.value)); | |
51 | } | |
52 | ||
eb39fafa DC |
53 | /** |
54 | * Whether this `meta` ObjectExpression has a `docs.recommended` property defined or not. | |
55 | * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. | |
56 | * @returns {boolean} `true` if a `docs.recommended` property exists. | |
57 | */ | |
58 | function hasMetaDocsRecommended(metaPropertyNode) { | |
59 | const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); | |
60 | ||
61 | return metaDocs && getPropertyFromObject("recommended", metaDocs.value); | |
62 | } | |
63 | ||
eb39fafa DC |
64 | /** |
65 | * Checks the validity of the meta definition of this rule and reports any errors found. | |
66 | * @param {RuleContext} context The ESLint rule context. | |
67 | * @param {ASTNode} exportsNode ObjectExpression node that the rule exports. | |
68 | * @returns {void} | |
69 | */ | |
70 | function checkMetaValidity(context, exportsNode) { | |
71 | const metaProperty = getMetaPropertyFromExportsNode(exportsNode); | |
72 | ||
73 | if (!metaProperty) { | |
74 | context.report({ node: exportsNode, messageId: "missingMeta" }); | |
75 | return; | |
76 | } | |
77 | ||
78 | if (!hasMetaDocs(metaProperty)) { | |
79 | context.report({ node: metaProperty, messageId: "missingMetaDocs" }); | |
80 | return; | |
81 | } | |
82 | ||
eb39fafa DC |
83 | if (!hasMetaDocsRecommended(metaProperty)) { |
84 | context.report({ node: metaProperty, messageId: "missingMetaDocsRecommended" }); | |
eb39fafa | 85 | } |
eb39fafa DC |
86 | } |
87 | ||
88 | //------------------------------------------------------------------------------ | |
89 | // Rule Definition | |
90 | //------------------------------------------------------------------------------ | |
91 | ||
92 | module.exports = { | |
93 | meta: { | |
94 | docs: { | |
95 | description: "enforce correct use of `meta` property in core rules", | |
eb39fafa DC |
96 | recommended: false |
97 | }, | |
98 | type: "problem", | |
99 | schema: [], | |
100 | messages: { | |
101 | missingMeta: "Rule is missing a meta property.", | |
102 | missingMetaDocs: "Rule is missing a meta.docs property.", | |
eb39fafa | 103 | missingMetaDocsRecommended: "Rule is missing a meta.docs.recommended property.", |
609c276f | 104 | noExport: "Rule does not export anything. Make sure rule exports an object according to new rule format." |
eb39fafa DC |
105 | } |
106 | }, | |
107 | ||
108 | create(context) { | |
109 | let exportsNode; | |
110 | ||
111 | return { | |
112 | AssignmentExpression(node) { | |
113 | if (node.left && | |
114 | node.right && | |
115 | node.left.type === "MemberExpression" && | |
116 | node.left.object.name === "module" && | |
117 | node.left.property.name === "exports") { | |
118 | ||
119 | exportsNode = node.right; | |
120 | } | |
121 | }, | |
122 | ||
123 | "Program:exit"(node) { | |
124 | if (!exportsNode) { | |
125 | context.report({ | |
126 | node, | |
127 | messageId: "noExport" | |
128 | }); | |
eb39fafa DC |
129 | } else { |
130 | checkMetaValidity(context, exportsNode); | |
131 | } | |
132 | } | |
133 | }; | |
134 | } | |
135 | }; |