Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

strict.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /**
  2. * @fileoverview Rule to control usage of strict mode directives.
  3. * @author Brandon Mills
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("../util/ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. const messages = {
  14. function: "Use the function form of 'use strict'.",
  15. global: "Use the global form of 'use strict'.",
  16. multiple: "Multiple 'use strict' directives.",
  17. never: "Strict mode is not permitted.",
  18. unnecessary: "Unnecessary 'use strict' directive.",
  19. module: "'use strict' is unnecessary inside of modules.",
  20. implied: "'use strict' is unnecessary when implied strict mode is enabled.",
  21. unnecessaryInClasses: "'use strict' is unnecessary inside of classes.",
  22. nonSimpleParameterList: "'use strict' directive inside a function with non-simple parameter list throws a syntax error since ES2016.",
  23. wrap: "Wrap {{name}} in a function with 'use strict' directive."
  24. };
  25. /**
  26. * Gets all of the Use Strict Directives in the Directive Prologue of a group of
  27. * statements.
  28. * @param {ASTNode[]} statements Statements in the program or function body.
  29. * @returns {ASTNode[]} All of the Use Strict Directives.
  30. */
  31. function getUseStrictDirectives(statements) {
  32. const directives = [];
  33. for (let i = 0; i < statements.length; i++) {
  34. const statement = statements[i];
  35. if (
  36. statement.type === "ExpressionStatement" &&
  37. statement.expression.type === "Literal" &&
  38. statement.expression.value === "use strict"
  39. ) {
  40. directives[i] = statement;
  41. } else {
  42. break;
  43. }
  44. }
  45. return directives;
  46. }
  47. /**
  48. * Checks whether a given parameter is a simple parameter.
  49. *
  50. * @param {ASTNode} node - A pattern node to check.
  51. * @returns {boolean} `true` if the node is an Identifier node.
  52. */
  53. function isSimpleParameter(node) {
  54. return node.type === "Identifier";
  55. }
  56. /**
  57. * Checks whether a given parameter list is a simple parameter list.
  58. *
  59. * @param {ASTNode[]} params - A parameter list to check.
  60. * @returns {boolean} `true` if the every parameter is an Identifier node.
  61. */
  62. function isSimpleParameterList(params) {
  63. return params.every(isSimpleParameter);
  64. }
  65. //------------------------------------------------------------------------------
  66. // Rule Definition
  67. //------------------------------------------------------------------------------
  68. module.exports = {
  69. meta: {
  70. type: "suggestion",
  71. docs: {
  72. description: "require or disallow strict mode directives",
  73. category: "Strict Mode",
  74. recommended: false,
  75. url: "https://eslint.org/docs/rules/strict"
  76. },
  77. schema: [
  78. {
  79. enum: ["never", "global", "function", "safe"]
  80. }
  81. ],
  82. fixable: "code"
  83. },
  84. create(context) {
  85. const ecmaFeatures = context.parserOptions.ecmaFeatures || {},
  86. scopes = [],
  87. classScopes = [];
  88. let mode = context.options[0] || "safe";
  89. if (ecmaFeatures.impliedStrict) {
  90. mode = "implied";
  91. } else if (mode === "safe") {
  92. mode = ecmaFeatures.globalReturn ? "global" : "function";
  93. }
  94. /**
  95. * Determines whether a reported error should be fixed, depending on the error type.
  96. * @param {string} errorType The type of error
  97. * @returns {boolean} `true` if the reported error should be fixed
  98. */
  99. function shouldFix(errorType) {
  100. return errorType === "multiple" || errorType === "unnecessary" || errorType === "module" || errorType === "implied" || errorType === "unnecessaryInClasses";
  101. }
  102. /**
  103. * Gets a fixer function to remove a given 'use strict' directive.
  104. * @param {ASTNode} node The directive that should be removed
  105. * @returns {Function} A fixer function
  106. */
  107. function getFixFunction(node) {
  108. return fixer => fixer.remove(node);
  109. }
  110. /**
  111. * Report a slice of an array of nodes with a given message.
  112. * @param {ASTNode[]} nodes Nodes.
  113. * @param {string} start Index to start from.
  114. * @param {string} end Index to end before.
  115. * @param {string} message Message to display.
  116. * @param {boolean} fix `true` if the directive should be fixed (i.e. removed)
  117. * @returns {void}
  118. */
  119. function reportSlice(nodes, start, end, message, fix) {
  120. nodes.slice(start, end).forEach(node => {
  121. context.report({ node, message, fix: fix ? getFixFunction(node) : null });
  122. });
  123. }
  124. /**
  125. * Report all nodes in an array with a given message.
  126. * @param {ASTNode[]} nodes Nodes.
  127. * @param {string} message Message to display.
  128. * @param {boolean} fix `true` if the directive should be fixed (i.e. removed)
  129. * @returns {void}
  130. */
  131. function reportAll(nodes, message, fix) {
  132. reportSlice(nodes, 0, nodes.length, message, fix);
  133. }
  134. /**
  135. * Report all nodes in an array, except the first, with a given message.
  136. * @param {ASTNode[]} nodes Nodes.
  137. * @param {string} message Message to display.
  138. * @param {boolean} fix `true` if the directive should be fixed (i.e. removed)
  139. * @returns {void}
  140. */
  141. function reportAllExceptFirst(nodes, message, fix) {
  142. reportSlice(nodes, 1, nodes.length, message, fix);
  143. }
  144. /**
  145. * Entering a function in 'function' mode pushes a new nested scope onto the
  146. * stack. The new scope is true if the nested function is strict mode code.
  147. * @param {ASTNode} node The function declaration or expression.
  148. * @param {ASTNode[]} useStrictDirectives The Use Strict Directives of the node.
  149. * @returns {void}
  150. */
  151. function enterFunctionInFunctionMode(node, useStrictDirectives) {
  152. const isInClass = classScopes.length > 0,
  153. isParentGlobal = scopes.length === 0 && classScopes.length === 0,
  154. isParentStrict = scopes.length > 0 && scopes[scopes.length - 1],
  155. isStrict = useStrictDirectives.length > 0;
  156. if (isStrict) {
  157. if (!isSimpleParameterList(node.params)) {
  158. context.report({ node: useStrictDirectives[0], message: messages.nonSimpleParameterList });
  159. } else if (isParentStrict) {
  160. context.report({ node: useStrictDirectives[0], message: messages.unnecessary, fix: getFixFunction(useStrictDirectives[0]) });
  161. } else if (isInClass) {
  162. context.report({ node: useStrictDirectives[0], message: messages.unnecessaryInClasses, fix: getFixFunction(useStrictDirectives[0]) });
  163. }
  164. reportAllExceptFirst(useStrictDirectives, messages.multiple, true);
  165. } else if (isParentGlobal) {
  166. if (isSimpleParameterList(node.params)) {
  167. context.report({ node, message: messages.function });
  168. } else {
  169. context.report({
  170. node,
  171. message: messages.wrap,
  172. data: { name: astUtils.getFunctionNameWithKind(node) }
  173. });
  174. }
  175. }
  176. scopes.push(isParentStrict || isStrict);
  177. }
  178. /**
  179. * Exiting a function in 'function' mode pops its scope off the stack.
  180. * @returns {void}
  181. */
  182. function exitFunctionInFunctionMode() {
  183. scopes.pop();
  184. }
  185. /**
  186. * Enter a function and either:
  187. * - Push a new nested scope onto the stack (in 'function' mode).
  188. * - Report all the Use Strict Directives (in the other modes).
  189. * @param {ASTNode} node The function declaration or expression.
  190. * @returns {void}
  191. */
  192. function enterFunction(node) {
  193. const isBlock = node.body.type === "BlockStatement",
  194. useStrictDirectives = isBlock
  195. ? getUseStrictDirectives(node.body.body) : [];
  196. if (mode === "function") {
  197. enterFunctionInFunctionMode(node, useStrictDirectives);
  198. } else if (useStrictDirectives.length > 0) {
  199. if (isSimpleParameterList(node.params)) {
  200. reportAll(useStrictDirectives, messages[mode], shouldFix(mode));
  201. } else {
  202. context.report({ node: useStrictDirectives[0], message: messages.nonSimpleParameterList });
  203. reportAllExceptFirst(useStrictDirectives, messages.multiple, true);
  204. }
  205. }
  206. }
  207. const rule = {
  208. Program(node) {
  209. const useStrictDirectives = getUseStrictDirectives(node.body);
  210. if (node.sourceType === "module") {
  211. mode = "module";
  212. }
  213. if (mode === "global") {
  214. if (node.body.length > 0 && useStrictDirectives.length === 0) {
  215. context.report({ node, message: messages.global });
  216. }
  217. reportAllExceptFirst(useStrictDirectives, messages.multiple, true);
  218. } else {
  219. reportAll(useStrictDirectives, messages[mode], shouldFix(mode));
  220. }
  221. },
  222. FunctionDeclaration: enterFunction,
  223. FunctionExpression: enterFunction,
  224. ArrowFunctionExpression: enterFunction
  225. };
  226. if (mode === "function") {
  227. Object.assign(rule, {
  228. // Inside of class bodies are always strict mode.
  229. ClassBody() {
  230. classScopes.push(true);
  231. },
  232. "ClassBody:exit"() {
  233. classScopes.pop();
  234. },
  235. "FunctionDeclaration:exit": exitFunctionInFunctionMode,
  236. "FunctionExpression:exit": exitFunctionInFunctionMode,
  237. "ArrowFunctionExpression:exit": exitFunctionInFunctionMode
  238. });
  239. }
  240. return rule;
  241. }
  242. };