]> git.proxmox.com Git - pve-eslint.git/blame - eslint/tools/internal-rules/no-invalid-meta.js
build upstream to umd
[pve-eslint.git] / eslint / tools / internal-rules / no-invalid-meta.js
CommitLineData
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 */
18function 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 */
40function 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 */
49function hasMetaDocs(metaPropertyNode) {
50 return Boolean(getPropertyFromObject("docs", metaPropertyNode.value));
51}
52
53/**
54 * Whether this `meta` ObjectExpression has a `docs.description` property defined or not.
55 * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
56 * @returns {boolean} `true` if a `docs.description` property exists.
57 */
58function hasMetaDocsDescription(metaPropertyNode) {
59 const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
60
61 return metaDocs && getPropertyFromObject("description", metaDocs.value);
62}
63
64/**
65 * Whether this `meta` ObjectExpression has a `docs.category` property defined or not.
66 * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
67 * @returns {boolean} `true` if a `docs.category` property exists.
68 */
69function hasMetaDocsCategory(metaPropertyNode) {
70 const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
71
72 return metaDocs && getPropertyFromObject("category", metaDocs.value);
73}
74
75/**
76 * Whether this `meta` ObjectExpression has a `docs.recommended` property defined or not.
77 * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
78 * @returns {boolean} `true` if a `docs.recommended` property exists.
79 */
80function hasMetaDocsRecommended(metaPropertyNode) {
81 const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
82
83 return metaDocs && getPropertyFromObject("recommended", metaDocs.value);
84}
85
86/**
87 * Whether this `meta` ObjectExpression has a `schema` property defined or not.
88 * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
89 * @returns {boolean} `true` if a `schema` property exists.
90 */
91function hasMetaSchema(metaPropertyNode) {
92 return getPropertyFromObject("schema", metaPropertyNode.value);
93}
94
95/**
96 * Checks the validity of the meta definition of this rule and reports any errors found.
97 * @param {RuleContext} context The ESLint rule context.
98 * @param {ASTNode} exportsNode ObjectExpression node that the rule exports.
99 * @returns {void}
100 */
101function checkMetaValidity(context, exportsNode) {
102 const metaProperty = getMetaPropertyFromExportsNode(exportsNode);
103
104 if (!metaProperty) {
105 context.report({ node: exportsNode, messageId: "missingMeta" });
106 return;
107 }
108
109 if (!hasMetaDocs(metaProperty)) {
110 context.report({ node: metaProperty, messageId: "missingMetaDocs" });
111 return;
112 }
113
114 if (!hasMetaDocsDescription(metaProperty)) {
115 context.report({ node: metaProperty, messageId: "missingMetaDocsDescription" });
116 return;
117 }
118
119 if (!hasMetaDocsCategory(metaProperty)) {
120 context.report({ node: metaProperty, messageId: "missingMetaDocsCategory" });
121 return;
122 }
123
124 if (!hasMetaDocsRecommended(metaProperty)) {
125 context.report({ node: metaProperty, messageId: "missingMetaDocsRecommended" });
126 return;
127 }
128
129 if (!hasMetaSchema(metaProperty)) {
130 context.report({ node: metaProperty, messageId: "missingMetaSchema" });
131 }
132}
133
134/**
135 * Whether this node is the correct format for a rule definition or not.
136 * @param {ASTNode} node node that the rule exports.
137 * @returns {boolean} `true` if the exported node is the correct format for a rule definition
138 */
139function isCorrectExportsFormat(node) {
140 return node.type === "ObjectExpression";
141}
142
143//------------------------------------------------------------------------------
144// Rule Definition
145//------------------------------------------------------------------------------
146
147module.exports = {
148 meta: {
149 docs: {
150 description: "enforce correct use of `meta` property in core rules",
151 category: "Internal",
152 recommended: false
153 },
154 type: "problem",
155 schema: [],
156 messages: {
157 missingMeta: "Rule is missing a meta property.",
158 missingMetaDocs: "Rule is missing a meta.docs property.",
159 missingMetaDocsDescription: "Rule is missing a meta.docs.description property.",
160 missingMetaDocsCategory: "Rule is missing a meta.docs.category property.",
161 missingMetaDocsRecommended: "Rule is missing a meta.docs.recommended property.",
162 missingMetaSchema: "Rule is missing a meta.schema property.",
163 noExport: "Rule does not export anything. Make sure rule exports an object according to new rule format.",
164 incorrectExport: "Rule does not export an Object. Make sure the rule follows the new rule format."
165 }
166 },
167
168 create(context) {
169 let exportsNode;
170
171 return {
172 AssignmentExpression(node) {
173 if (node.left &&
174 node.right &&
175 node.left.type === "MemberExpression" &&
176 node.left.object.name === "module" &&
177 node.left.property.name === "exports") {
178
179 exportsNode = node.right;
180 }
181 },
182
183 "Program:exit"(node) {
184 if (!exportsNode) {
185 context.report({
186 node,
187 messageId: "noExport"
188 });
189 } else if (!isCorrectExportsFormat(exportsNode)) {
190 context.report({
191 node: exportsNode,
192 messageId: "incorrectExport"
193 });
194 } else {
195 checkMetaValidity(context, exportsNode);
196 }
197 }
198 };
199 }
200};