jsx-filename-extension.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /**
  2. * @fileoverview Restrict file extensions that may contain JSX
  3. * @author Joe Lencioni
  4. */
  5. 'use strict';
  6. const path = require('path');
  7. const docsUrl = require('../util/docsUrl');
  8. // ------------------------------------------------------------------------------
  9. // Constants
  10. // ------------------------------------------------------------------------------
  11. const DEFAULTS = {
  12. allow: 'always',
  13. extensions: ['.jsx']
  14. };
  15. // ------------------------------------------------------------------------------
  16. // Rule Definition
  17. // ------------------------------------------------------------------------------
  18. module.exports = {
  19. meta: {
  20. docs: {
  21. description: 'Restrict file extensions that may contain JSX',
  22. category: 'Stylistic Issues',
  23. recommended: false,
  24. url: docsUrl('jsx-filename-extension')
  25. },
  26. messages: {
  27. noJSXWithExtension: 'JSX not allowed in files with extension \'{{ext}}\'',
  28. extensionOnlyForJSX: 'Only files containing JSX may use the extension \'{{ext}}\''
  29. },
  30. schema: [{
  31. type: 'object',
  32. properties: {
  33. allow: {
  34. enum: ['always', 'as-needed']
  35. },
  36. extensions: {
  37. type: 'array',
  38. items: {
  39. type: 'string'
  40. }
  41. }
  42. },
  43. additionalProperties: false
  44. }]
  45. },
  46. create(context) {
  47. const filename = context.getFilename();
  48. let jsxNode;
  49. if (filename === '<text>') {
  50. // No need to traverse any nodes.
  51. return {};
  52. }
  53. const allow = (context.options[0] && context.options[0].allow) || DEFAULTS.allow;
  54. const allowedExtensions = (context.options[0] && context.options[0].extensions) || DEFAULTS.extensions;
  55. const isAllowedExtension = allowedExtensions.some((extension) => filename.slice(-extension.length) === extension);
  56. function handleJSX(node) {
  57. if (!jsxNode) {
  58. jsxNode = node;
  59. }
  60. }
  61. // --------------------------------------------------------------------------
  62. // Public
  63. // --------------------------------------------------------------------------
  64. return {
  65. JSXElement: handleJSX,
  66. JSXFragment: handleJSX,
  67. 'Program:exit'(node) {
  68. if (jsxNode) {
  69. if (!isAllowedExtension) {
  70. context.report({
  71. node: jsxNode,
  72. messageId: 'noJSXWithExtension',
  73. data: {
  74. ext: path.extname(filename)
  75. }
  76. });
  77. }
  78. return;
  79. }
  80. if (isAllowedExtension && allow === 'as-needed') {
  81. context.report({
  82. node,
  83. messageId: 'extensionOnlyForJSX',
  84. data: {
  85. ext: path.extname(filename)
  86. }
  87. });
  88. }
  89. }
  90. };
  91. }
  92. };