mustache-interpolation-spacing.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /**
  2. * @fileoverview enforce unified spacing in mustache interpolations.
  3. * @author Armano
  4. */
  5. 'use strict'
  6. // ------------------------------------------------------------------------------
  7. // Requirements
  8. // ------------------------------------------------------------------------------
  9. const utils = require('../utils')
  10. // ------------------------------------------------------------------------------
  11. // Rule Definition
  12. // ------------------------------------------------------------------------------
  13. module.exports = {
  14. meta: {
  15. type: 'layout',
  16. docs: {
  17. description: 'enforce unified spacing in mustache interpolations',
  18. category: 'strongly-recommended',
  19. url: 'https://eslint.vuejs.org/rules/mustache-interpolation-spacing.html'
  20. },
  21. fixable: 'whitespace',
  22. schema: [
  23. {
  24. enum: ['always', 'never']
  25. }
  26. ]
  27. },
  28. create (context) {
  29. const options = context.options[0] || 'always'
  30. const template =
  31. context.parserServices.getTemplateBodyTokenStore &&
  32. context.parserServices.getTemplateBodyTokenStore()
  33. // ----------------------------------------------------------------------
  34. // Public
  35. // ----------------------------------------------------------------------
  36. return utils.defineTemplateBodyVisitor(context, {
  37. 'VExpressionContainer[expression!=null]' (node) {
  38. const openBrace = template.getFirstToken(node)
  39. const closeBrace = template.getLastToken(node)
  40. if (
  41. !openBrace ||
  42. !closeBrace ||
  43. openBrace.type !== 'VExpressionStart' ||
  44. closeBrace.type !== 'VExpressionEnd'
  45. ) {
  46. return
  47. }
  48. const firstToken = template.getTokenAfter(openBrace, { includeComments: true })
  49. const lastToken = template.getTokenBefore(closeBrace, { includeComments: true })
  50. if (options === 'always') {
  51. if (openBrace.range[1] === firstToken.range[0]) {
  52. context.report({
  53. node: openBrace,
  54. message: "Expected 1 space after '{{', but not found.",
  55. fix: (fixer) => fixer.insertTextAfter(openBrace, ' ')
  56. })
  57. }
  58. if (closeBrace.range[0] === lastToken.range[1]) {
  59. context.report({
  60. node: closeBrace,
  61. message: "Expected 1 space before '}}', but not found.",
  62. fix: (fixer) => fixer.insertTextBefore(closeBrace, ' ')
  63. })
  64. }
  65. } else {
  66. if (openBrace.range[1] !== firstToken.range[0]) {
  67. context.report({
  68. loc: {
  69. start: openBrace.loc.start,
  70. end: firstToken.loc.start
  71. },
  72. message: "Expected no space after '{{', but found.",
  73. fix: (fixer) => fixer.removeRange([openBrace.range[1], firstToken.range[0]])
  74. })
  75. }
  76. if (closeBrace.range[0] !== lastToken.range[1]) {
  77. context.report({
  78. loc: {
  79. start: lastToken.loc.end,
  80. end: closeBrace.loc.end
  81. },
  82. message: "Expected no space before '}}', but found.",
  83. fix: (fixer) => fixer.removeRange([lastToken.range[1], closeBrace.range[0]])
  84. })
  85. }
  86. }
  87. }
  88. })
  89. }
  90. }