no-redundant-story-name.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. "use strict";
  2. /**
  3. * @fileoverview Named exports should not use the name annotation if it is redundant to the name that would be generated by the export name
  4. * @author Yann Braga
  5. */
  6. const csf_1 = require("@storybook/csf");
  7. const ast_1 = require("../utils/ast");
  8. const constants_1 = require("../utils/constants");
  9. const create_storybook_rule_1 = require("../utils/create-storybook-rule");
  10. module.exports = (0, create_storybook_rule_1.createStorybookRule)({
  11. name: 'no-redundant-story-name',
  12. defaultOptions: [],
  13. meta: {
  14. type: 'suggestion',
  15. fixable: 'code',
  16. hasSuggestions: true,
  17. docs: {
  18. description: 'A story should not have a redundant name property',
  19. categories: [constants_1.CategoryId.CSF, constants_1.CategoryId.RECOMMENDED],
  20. recommended: 'warn',
  21. },
  22. messages: {
  23. removeRedundantName: 'Remove redundant name',
  24. storyNameIsRedundant: 'Named exports should not use the name annotation if it is redundant to the name that would be generated by the export name',
  25. },
  26. schema: [],
  27. },
  28. create(context) {
  29. //----------------------------------------------------------------------
  30. // Public
  31. //----------------------------------------------------------------------
  32. return {
  33. // CSF3
  34. ExportNamedDeclaration: function (node) {
  35. // if there are specifiers, node.declaration should be null
  36. if (!node.declaration)
  37. return;
  38. const decl = node.declaration;
  39. if ((0, ast_1.isVariableDeclaration)(decl)) {
  40. const declaration = decl.declarations[0];
  41. if (declaration == null)
  42. return;
  43. const { id, init } = declaration;
  44. if ((0, ast_1.isIdentifier)(id) && (0, ast_1.isObjectExpression)(init)) {
  45. const storyNameNode = init.properties.find((prop) => {
  46. var _a, _b;
  47. return (0, ast_1.isProperty)(prop) &&
  48. (0, ast_1.isIdentifier)(prop.key) &&
  49. (((_a = prop.key) === null || _a === void 0 ? void 0 : _a.name) === 'name' || ((_b = prop.key) === null || _b === void 0 ? void 0 : _b.name) === 'storyName');
  50. });
  51. if (!storyNameNode) {
  52. return;
  53. }
  54. const { name } = id;
  55. const resolvedStoryName = (0, csf_1.storyNameFromExport)(name);
  56. if (!(0, ast_1.isSpreadElement)(storyNameNode) &&
  57. (0, ast_1.isLiteral)(storyNameNode.value) &&
  58. storyNameNode.value.value === resolvedStoryName) {
  59. context.report({
  60. node: storyNameNode,
  61. messageId: 'storyNameIsRedundant',
  62. suggest: [
  63. {
  64. messageId: 'removeRedundantName',
  65. fix: function (fixer) {
  66. return fixer.remove(storyNameNode);
  67. },
  68. },
  69. ],
  70. });
  71. }
  72. }
  73. }
  74. },
  75. // CSF2
  76. AssignmentExpression: function (node) {
  77. if (!(0, ast_1.isExpressionStatement)(node.parent))
  78. return;
  79. const { left, right } = node;
  80. if ('property' in left &&
  81. (0, ast_1.isIdentifier)(left.property) &&
  82. !(0, ast_1.isMetaProperty)(left) &&
  83. left.property.name === 'storyName') {
  84. if (!('name' in left.object && 'value' in right))
  85. return;
  86. const propertyName = left.object.name;
  87. const propertyValue = right.value;
  88. const resolvedStoryName = (0, csf_1.storyNameFromExport)(propertyName);
  89. if (propertyValue === resolvedStoryName) {
  90. context.report({
  91. node: node,
  92. messageId: 'storyNameIsRedundant',
  93. suggest: [
  94. {
  95. messageId: 'removeRedundantName',
  96. fix: function (fixer) {
  97. return fixer.remove(node);
  98. },
  99. },
  100. ],
  101. });
  102. }
  103. }
  104. },
  105. };
  106. },
  107. });