no-multi-spaces.js 2.9 KB

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