项目原始demo,不改动
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

преди 4 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /**
  2. * @fileoverview Disallows or enforces spaces inside of object literals.
  3. * @author Jamund Ferguson
  4. */
  5. "use strict";
  6. const astUtils = require("../ast-utils");
  7. //------------------------------------------------------------------------------
  8. // Rule Definition
  9. //------------------------------------------------------------------------------
  10. module.exports = {
  11. meta: {
  12. docs: {
  13. description: "enforce consistent spacing inside braces",
  14. category: "Stylistic Issues",
  15. recommended: false,
  16. url: "https://eslint.org/docs/rules/object-curly-spacing"
  17. },
  18. fixable: "whitespace",
  19. schema: [
  20. {
  21. enum: ["always", "never"]
  22. },
  23. {
  24. type: "object",
  25. properties: {
  26. arraysInObjects: {
  27. type: "boolean"
  28. },
  29. objectsInObjects: {
  30. type: "boolean"
  31. }
  32. },
  33. additionalProperties: false
  34. }
  35. ]
  36. },
  37. create(context) {
  38. const spaced = context.options[0] === "always",
  39. sourceCode = context.getSourceCode();
  40. /**
  41. * Determines whether an option is set, relative to the spacing option.
  42. * If spaced is "always", then check whether option is set to false.
  43. * If spaced is "never", then check whether option is set to true.
  44. * @param {Object} option - The option to exclude.
  45. * @returns {boolean} Whether or not the property is excluded.
  46. */
  47. function isOptionSet(option) {
  48. return context.options[1] ? context.options[1][option] === !spaced : false;
  49. }
  50. const options = {
  51. spaced,
  52. arraysInObjectsException: isOptionSet("arraysInObjects"),
  53. objectsInObjectsException: isOptionSet("objectsInObjects")
  54. };
  55. //--------------------------------------------------------------------------
  56. // Helpers
  57. //--------------------------------------------------------------------------
  58. /**
  59. * Reports that there shouldn't be a space after the first token
  60. * @param {ASTNode} node - The node to report in the event of an error.
  61. * @param {Token} token - The token to use for the report.
  62. * @returns {void}
  63. */
  64. function reportNoBeginningSpace(node, token) {
  65. context.report({
  66. node,
  67. loc: token.loc.start,
  68. message: "There should be no space after '{{token}}'.",
  69. data: {
  70. token: token.value
  71. },
  72. fix(fixer) {
  73. const nextToken = context.getSourceCode().getTokenAfter(token);
  74. return fixer.removeRange([token.range[1], nextToken.range[0]]);
  75. }
  76. });
  77. }
  78. /**
  79. * Reports that there shouldn't be a space before the last token
  80. * @param {ASTNode} node - The node to report in the event of an error.
  81. * @param {Token} token - The token to use for the report.
  82. * @returns {void}
  83. */
  84. function reportNoEndingSpace(node, token) {
  85. context.report({
  86. node,
  87. loc: token.loc.start,
  88. message: "There should be no space before '{{token}}'.",
  89. data: {
  90. token: token.value
  91. },
  92. fix(fixer) {
  93. const previousToken = context.getSourceCode().getTokenBefore(token);
  94. return fixer.removeRange([previousToken.range[1], token.range[0]]);
  95. }
  96. });
  97. }
  98. /**
  99. * Reports that there should be a space after the first token
  100. * @param {ASTNode} node - The node to report in the event of an error.
  101. * @param {Token} token - The token to use for the report.
  102. * @returns {void}
  103. */
  104. function reportRequiredBeginningSpace(node, token) {
  105. context.report({
  106. node,
  107. loc: token.loc.start,
  108. message: "A space is required after '{{token}}'.",
  109. data: {
  110. token: token.value
  111. },
  112. fix(fixer) {
  113. return fixer.insertTextAfter(token, " ");
  114. }
  115. });
  116. }
  117. /**
  118. * Reports that there should be a space before the last token
  119. * @param {ASTNode} node - The node to report in the event of an error.
  120. * @param {Token} token - The token to use for the report.
  121. * @returns {void}
  122. */
  123. function reportRequiredEndingSpace(node, token) {
  124. context.report({
  125. node,
  126. loc: token.loc.start,
  127. message: "A space is required before '{{token}}'.",
  128. data: {
  129. token: token.value
  130. },
  131. fix(fixer) {
  132. return fixer.insertTextBefore(token, " ");
  133. }
  134. });
  135. }
  136. /**
  137. * Determines if spacing in curly braces is valid.
  138. * @param {ASTNode} node The AST node to check.
  139. * @param {Token} first The first token to check (should be the opening brace)
  140. * @param {Token} second The second token to check (should be first after the opening brace)
  141. * @param {Token} penultimate The penultimate token to check (should be last before closing brace)
  142. * @param {Token} last The last token to check (should be closing brace)
  143. * @returns {void}
  144. */
  145. function validateBraceSpacing(node, first, second, penultimate, last) {
  146. if (astUtils.isTokenOnSameLine(first, second)) {
  147. const firstSpaced = sourceCode.isSpaceBetweenTokens(first, second);
  148. if (options.spaced && !firstSpaced) {
  149. reportRequiredBeginningSpace(node, first);
  150. }
  151. if (!options.spaced && firstSpaced) {
  152. reportNoBeginningSpace(node, first);
  153. }
  154. }
  155. if (astUtils.isTokenOnSameLine(penultimate, last)) {
  156. const shouldCheckPenultimate = (
  157. options.arraysInObjectsException && astUtils.isClosingBracketToken(penultimate) ||
  158. options.objectsInObjectsException && astUtils.isClosingBraceToken(penultimate)
  159. );
  160. const penultimateType = shouldCheckPenultimate && sourceCode.getNodeByRangeIndex(penultimate.range[0]).type;
  161. const closingCurlyBraceMustBeSpaced = (
  162. options.arraysInObjectsException && penultimateType === "ArrayExpression" ||
  163. options.objectsInObjectsException && (penultimateType === "ObjectExpression" || penultimateType === "ObjectPattern")
  164. ) ? !options.spaced : options.spaced;
  165. const lastSpaced = sourceCode.isSpaceBetweenTokens(penultimate, last);
  166. if (closingCurlyBraceMustBeSpaced && !lastSpaced) {
  167. reportRequiredEndingSpace(node, last);
  168. }
  169. if (!closingCurlyBraceMustBeSpaced && lastSpaced) {
  170. reportNoEndingSpace(node, last);
  171. }
  172. }
  173. }
  174. /**
  175. * Gets '}' token of an object node.
  176. *
  177. * Because the last token of object patterns might be a type annotation,
  178. * this traverses tokens preceded by the last property, then returns the
  179. * first '}' token.
  180. *
  181. * @param {ASTNode} node - The node to get. This node is an
  182. * ObjectExpression or an ObjectPattern. And this node has one or
  183. * more properties.
  184. * @returns {Token} '}' token.
  185. */
  186. function getClosingBraceOfObject(node) {
  187. const lastProperty = node.properties[node.properties.length - 1];
  188. return sourceCode.getTokenAfter(lastProperty, astUtils.isClosingBraceToken);
  189. }
  190. /**
  191. * Reports a given object node if spacing in curly braces is invalid.
  192. * @param {ASTNode} node - An ObjectExpression or ObjectPattern node to check.
  193. * @returns {void}
  194. */
  195. function checkForObject(node) {
  196. if (node.properties.length === 0) {
  197. return;
  198. }
  199. const first = sourceCode.getFirstToken(node),
  200. last = getClosingBraceOfObject(node),
  201. second = sourceCode.getTokenAfter(first),
  202. penultimate = sourceCode.getTokenBefore(last);
  203. validateBraceSpacing(node, first, second, penultimate, last);
  204. }
  205. /**
  206. * Reports a given import node if spacing in curly braces is invalid.
  207. * @param {ASTNode} node - An ImportDeclaration node to check.
  208. * @returns {void}
  209. */
  210. function checkForImport(node) {
  211. if (node.specifiers.length === 0) {
  212. return;
  213. }
  214. let firstSpecifier = node.specifiers[0];
  215. const lastSpecifier = node.specifiers[node.specifiers.length - 1];
  216. if (lastSpecifier.type !== "ImportSpecifier") {
  217. return;
  218. }
  219. if (firstSpecifier.type !== "ImportSpecifier") {
  220. firstSpecifier = node.specifiers[1];
  221. }
  222. const first = sourceCode.getTokenBefore(firstSpecifier),
  223. last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
  224. second = sourceCode.getTokenAfter(first),
  225. penultimate = sourceCode.getTokenBefore(last);
  226. validateBraceSpacing(node, first, second, penultimate, last);
  227. }
  228. /**
  229. * Reports a given export node if spacing in curly braces is invalid.
  230. * @param {ASTNode} node - An ExportNamedDeclaration node to check.
  231. * @returns {void}
  232. */
  233. function checkForExport(node) {
  234. if (node.specifiers.length === 0) {
  235. return;
  236. }
  237. const firstSpecifier = node.specifiers[0],
  238. lastSpecifier = node.specifiers[node.specifiers.length - 1],
  239. first = sourceCode.getTokenBefore(firstSpecifier),
  240. last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
  241. second = sourceCode.getTokenAfter(first),
  242. penultimate = sourceCode.getTokenBefore(last);
  243. validateBraceSpacing(node, first, second, penultimate, last);
  244. }
  245. //--------------------------------------------------------------------------
  246. // Public
  247. //--------------------------------------------------------------------------
  248. return {
  249. // var {x} = y;
  250. ObjectPattern: checkForObject,
  251. // var y = {x: 'y'}
  252. ObjectExpression: checkForObject,
  253. // import {y} from 'x';
  254. ImportDeclaration: checkForImport,
  255. // export {name} from 'yo';
  256. ExportNamedDeclaration: checkForExport
  257. };
  258. }
  259. };