]> git.proxmox.com Git - pve-eslint.git/blame - eslint/lib/rules/no-restricted-modules.js
bump version to 7.0.0~alpha3-2
[pve-eslint.git] / eslint / lib / rules / no-restricted-modules.js
CommitLineData
eb39fafa
DC
1/**
2 * @fileoverview Restrict usage of specified node modules.
3 * @author Christian Schulz
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Rule Definition
9//------------------------------------------------------------------------------
10
11const ignore = require("ignore");
12
13const arrayOfStrings = {
14 type: "array",
15 items: { type: "string" },
16 uniqueItems: true
17};
18
19const arrayOfStringsOrObjects = {
20 type: "array",
21 items: {
22 anyOf: [
23 { type: "string" },
24 {
25 type: "object",
26 properties: {
27 name: { type: "string" },
28 message: {
29 type: "string",
30 minLength: 1
31 }
32 },
33 additionalProperties: false,
34 required: ["name"]
35 }
36 ]
37 },
38 uniqueItems: true
39};
40
41module.exports = {
42 meta: {
43 type: "suggestion",
44
45 docs: {
46 description: "disallow specified modules when loaded by `require`",
47 category: "Node.js and CommonJS",
48 recommended: false,
49 url: "https://eslint.org/docs/rules/no-restricted-modules"
50 },
51
52 schema: {
53 anyOf: [
54 arrayOfStringsOrObjects,
55 {
56 type: "array",
57 items: {
58 type: "object",
59 properties: {
60 paths: arrayOfStringsOrObjects,
61 patterns: arrayOfStrings
62 },
63 additionalProperties: false
64 },
65 additionalItems: false
66 }
67 ]
68 },
69
70 messages: {
71 defaultMessage: "'{{name}}' module is restricted from being used.",
72 // eslint-disable-next-line eslint-plugin/report-message-format
73 customMessage: "'{{name}}' module is restricted from being used. {{customMessage}}",
74 patternMessage: "'{{name}}' module is restricted from being used by a pattern."
75 }
76 },
77
78 create(context) {
79 const options = Array.isArray(context.options) ? context.options : [];
80 const isPathAndPatternsObject =
81 typeof options[0] === "object" &&
82 (Object.prototype.hasOwnProperty.call(options[0], "paths") || Object.prototype.hasOwnProperty.call(options[0], "patterns"));
83
84 const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
85 const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
86
87 const restrictedPathMessages = restrictedPaths.reduce((memo, importName) => {
88 if (typeof importName === "string") {
89 memo[importName] = null;
90 } else {
91 memo[importName.name] = importName.message;
92 }
93 return memo;
94 }, {});
95
96 // if no imports are restricted we don"t need to check
97 if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) {
98 return {};
99 }
100
101 const ig = ignore().add(restrictedPatterns);
102
103
104 /**
105 * Function to check if a node is a string literal.
106 * @param {ASTNode} node The node to check.
107 * @returns {boolean} If the node is a string literal.
108 */
109 function isStringLiteral(node) {
110 return node && node.type === "Literal" && typeof node.value === "string";
111 }
112
113 /**
114 * Function to check if a node is a static string template literal.
115 * @param {ASTNode} node The node to check.
116 * @returns {boolean} If the node is a string template literal.
117 */
118 function isStaticTemplateLiteral(node) {
119 return node && node.type === "TemplateLiteral" && node.expressions.length === 0;
120 }
121
122 /**
123 * Function to check if a node is a require call.
124 * @param {ASTNode} node The node to check.
125 * @returns {boolean} If the node is a require call.
126 */
127 function isRequireCall(node) {
128 return node.callee.type === "Identifier" && node.callee.name === "require";
129 }
130
131 /**
132 * Extract string from Literal or TemplateLiteral node
133 * @param {ASTNode} node The node to extract from
134 * @returns {string|null} Extracted string or null if node doesn't represent a string
135 */
136 function getFirstArgumentString(node) {
137 if (isStringLiteral(node)) {
138 return node.value.trim();
139 }
140
141 if (isStaticTemplateLiteral(node)) {
142 return node.quasis[0].value.cooked.trim();
143 }
144
145 return null;
146 }
147
148 /**
149 * Report a restricted path.
150 * @param {node} node representing the restricted path reference
151 * @param {string} name restricted path
152 * @returns {void}
153 * @private
154 */
155 function reportPath(node, name) {
156 const customMessage = restrictedPathMessages[name];
157 const messageId = customMessage
158 ? "customMessage"
159 : "defaultMessage";
160
161 context.report({
162 node,
163 messageId,
164 data: {
165 name,
166 customMessage
167 }
168 });
169 }
170
171 /**
172 * Check if the given name is a restricted path name
173 * @param {string} name name of a variable
174 * @returns {boolean} whether the variable is a restricted path or not
175 * @private
176 */
177 function isRestrictedPath(name) {
178 return Object.prototype.hasOwnProperty.call(restrictedPathMessages, name);
179 }
180
181 return {
182 CallExpression(node) {
183 if (isRequireCall(node)) {
184
185 // node has arguments
186 if (node.arguments.length) {
187 const name = getFirstArgumentString(node.arguments[0]);
188
189 // if first argument is a string literal or a static string template literal
190 if (name) {
191
192 // check if argument value is in restricted modules array
193 if (isRestrictedPath(name)) {
194 reportPath(node, name);
195 }
196
197 if (restrictedPatterns.length > 0 && ig.ignores(name)) {
198 context.report({
199 node,
200 messageId: "patternMessage",
201 data: { name }
202 });
203 }
204 }
205 }
206 }
207 }
208 };
209 }
210};