no-multi-spaces.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /**
  2. * @fileoverview This rule warns about the usage of extra whitespaces between attributes
  3. * @author Armano
  4. */
  5. 'use strict'
  6. const path = require('path')
  7. // ------------------------------------------------------------------------------
  8. // Rule Definition
  9. // ------------------------------------------------------------------------------
  10. /**
  11. * @param {RuleContext} context
  12. * @param {Token} node
  13. */
  14. const isProperty = (context, node) => {
  15. const sourceCode = context.getSourceCode()
  16. return node.type === 'Punctuator' && sourceCode.getText(node) === ':'
  17. }
  18. module.exports = {
  19. meta: {
  20. type: 'layout',
  21. docs: {
  22. description: 'disallow multiple spaces',
  23. categories: ['vue3-strongly-recommended', 'strongly-recommended'],
  24. url: 'https://eslint.vuejs.org/rules/no-multi-spaces.html'
  25. },
  26. fixable: 'whitespace', // or "code" or "whitespace"
  27. schema: [
  28. {
  29. type: 'object',
  30. properties: {
  31. ignoreProperties: {
  32. type: 'boolean'
  33. }
  34. },
  35. additionalProperties: false
  36. }
  37. ]
  38. },
  39. /**
  40. * @param {RuleContext} context - The rule context.
  41. * @returns {RuleListener} AST event handlers.
  42. */
  43. create(context) {
  44. const options = context.options[0] || {}
  45. const ignoreProperties = options.ignoreProperties === true
  46. return {
  47. Program(node) {
  48. if (context.parserServices.getTemplateBodyTokenStore == null) {
  49. const filename = context.getFilename()
  50. if (path.extname(filename) === '.vue') {
  51. context.report({
  52. loc: { line: 1, column: 0 },
  53. message:
  54. 'Use the latest vue-eslint-parser. See also https://eslint.vuejs.org/user-guide/#what-is-the-use-the-latest-vue-eslint-parser-error.'
  55. })
  56. }
  57. return
  58. }
  59. if (!node.templateBody) {
  60. return
  61. }
  62. const sourceCode = context.getSourceCode()
  63. const tokenStore = context.parserServices.getTemplateBodyTokenStore()
  64. const tokens = tokenStore.getTokens(node.templateBody, {
  65. includeComments: true
  66. })
  67. let prevToken = /** @type {Token} */ (tokens.shift())
  68. for (const token of tokens) {
  69. const spaces = token.range[0] - prevToken.range[1]
  70. const shouldIgnore =
  71. ignoreProperties &&
  72. (isProperty(context, token) || isProperty(context, prevToken))
  73. if (
  74. spaces > 1 &&
  75. token.loc.start.line === prevToken.loc.start.line &&
  76. !shouldIgnore
  77. ) {
  78. context.report({
  79. node: token,
  80. loc: {
  81. start: prevToken.loc.end,
  82. end: token.loc.start
  83. },
  84. message: "Multiple spaces found before '{{displayValue}}'.",
  85. fix: (fixer) =>
  86. fixer.replaceTextRange(
  87. [prevToken.range[1], token.range[0]],
  88. ' '
  89. ),
  90. data: {
  91. displayValue: sourceCode.getText(token)
  92. }
  93. })
  94. }
  95. prevToken = token
  96. }
  97. }
  98. }
  99. }
  100. }