slot-name-casing.js 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /**
  2. * @author Wayne Zhang
  3. * See LICENSE file in root directory for full license.
  4. */
  5. 'use strict'
  6. const utils = require('../utils')
  7. const casing = require('../utils/casing')
  8. /**
  9. * @typedef { 'camelCase' | 'kebab-case' | 'singleword' } OptionType
  10. * @typedef { (str: string) => boolean } CheckerType
  11. */
  12. /**
  13. * Checks whether the given string is a single word.
  14. * @param {string} str
  15. * @return {boolean}
  16. */
  17. function isSingleWord(str) {
  18. return /^[a-z]+$/u.test(str)
  19. }
  20. /** @type {OptionType[]} */
  21. const allowedCaseOptions = ['camelCase', 'kebab-case', 'singleword']
  22. module.exports = {
  23. meta: {
  24. type: 'suggestion',
  25. docs: {
  26. description: 'enforce specific casing for slot names',
  27. categories: undefined,
  28. url: 'https://eslint.vuejs.org/rules/slot-name-casing.html'
  29. },
  30. fixable: null,
  31. schema: [
  32. {
  33. enum: allowedCaseOptions
  34. }
  35. ],
  36. messages: {
  37. invalidCase: 'Slot name "{{name}}" is not {{caseType}}.'
  38. }
  39. },
  40. /** @param {RuleContext} context */
  41. create(context) {
  42. const option = context.options[0]
  43. /** @type {OptionType} */
  44. const caseType = allowedCaseOptions.includes(option) ? option : 'camelCase'
  45. /** @type {CheckerType} */
  46. const checker =
  47. caseType === 'singleword' ? isSingleWord : casing.getChecker(caseType)
  48. /** @param {VAttribute} node */
  49. function processSlotNode(node) {
  50. const name = node.value?.value
  51. if (name && !checker(name)) {
  52. context.report({
  53. node,
  54. loc: node.loc,
  55. messageId: 'invalidCase',
  56. data: {
  57. name,
  58. caseType
  59. }
  60. })
  61. }
  62. }
  63. return utils.defineTemplateBodyVisitor(context, {
  64. /** @param {VElement} node */
  65. "VElement[name='slot']"(node) {
  66. const slotName = utils.getAttribute(node, 'name')
  67. if (slotName) {
  68. processSlotNode(slotName)
  69. }
  70. }
  71. })
  72. }
  73. }