genericSpacing.js.flow 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import {
  2. spacingFixers,
  3. } from '../utilities';
  4. const schema = [
  5. {
  6. enum: ['always', 'never'],
  7. type: 'string',
  8. },
  9. ];
  10. const create = (context) => {
  11. const sourceCode = context.getSourceCode();
  12. const never = (context.options[0] || 'never') === 'never';
  13. return {
  14. GenericTypeAnnotation(node) {
  15. const types = node.typeParameters;
  16. // Promise<foo>
  17. // ^^^^^^^^^^^^ GenericTypeAnnotation (with typeParameters)
  18. // ^^^ GenericTypeAnnotation (without typeParameters)
  19. if (!types) {
  20. return;
  21. }
  22. const [opener, firstInnerToken] = sourceCode.getFirstTokens(types, 2);
  23. const [lastInnerToken, closer] = sourceCode.getLastTokens(types, 2);
  24. const spacesBefore = firstInnerToken.range[0] - opener.range[1];
  25. const spacesAfter = closer.range[0] - lastInnerToken.range[1];
  26. if (never) {
  27. if (spacesBefore) {
  28. const whiteSpaceBefore = sourceCode.text[opener.range[1]];
  29. if (whiteSpaceBefore !== '\n' && whiteSpaceBefore !== '\r') {
  30. context.report({
  31. data: { name: node.id.name },
  32. fix: spacingFixers.stripSpacesAfter(opener, spacesBefore),
  33. message: 'There must be no space at start of "{{name}}" generic type annotation',
  34. node: types,
  35. });
  36. }
  37. }
  38. if (spacesAfter) {
  39. const whiteSpaceAfter = sourceCode.text[closer.range[0] - 1];
  40. if (whiteSpaceAfter !== '\n' && whiteSpaceAfter !== '\r') {
  41. context.report({
  42. data: { name: node.id.name },
  43. fix: spacingFixers.stripSpacesAfter(lastInnerToken, spacesAfter),
  44. message: 'There must be no space at end of "{{name}}" generic type annotation',
  45. node: types,
  46. });
  47. }
  48. }
  49. } else {
  50. if (spacesBefore > 1) {
  51. context.report({
  52. data: { name: node.id.name },
  53. fix: spacingFixers.stripSpacesAfter(opener, spacesBefore - 1),
  54. message: 'There must be one space at start of "{{name}}" generic type annotation',
  55. node: types,
  56. });
  57. } else if (spacesBefore === 0) {
  58. context.report({
  59. data: { name: node.id.name },
  60. fix: spacingFixers.addSpaceAfter(opener),
  61. message: 'There must be a space at start of "{{name}}" generic type annotation',
  62. node: types,
  63. });
  64. }
  65. if (spacesAfter > 1) {
  66. context.report({
  67. data: { name: node.id.name },
  68. fix: spacingFixers.stripSpacesAfter(lastInnerToken, spacesAfter - 1),
  69. message: 'There must be one space at end of "{{name}}" generic type annotation',
  70. node: types,
  71. });
  72. } else if (spacesAfter === 0) {
  73. context.report({
  74. data: { name: node.id.name },
  75. fix: spacingFixers.addSpaceAfter(lastInnerToken),
  76. message: 'There must be a space at end of "{{name}}" generic type annotation',
  77. node: types,
  78. });
  79. }
  80. }
  81. },
  82. };
  83. };
  84. const meta = {
  85. fixable: 'whitespace',
  86. };
  87. export default {
  88. create,
  89. meta,
  90. schema,
  91. };