multiline-ternary.js 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /**
  2. * @fileoverview Enforce newlines between operands of ternary expressions
  3. * @author Kai Cataldo
  4. */
  5. "use strict";
  6. const astUtils = require("./utils/ast-utils");
  7. //------------------------------------------------------------------------------
  8. // Rule Definition
  9. //------------------------------------------------------------------------------
  10. module.exports = {
  11. meta: {
  12. type: "layout",
  13. docs: {
  14. description: "enforce newlines between operands of ternary expressions",
  15. category: "Stylistic Issues",
  16. recommended: false,
  17. url: "https://eslint.org/docs/rules/multiline-ternary"
  18. },
  19. schema: [
  20. {
  21. enum: ["always", "always-multiline", "never"]
  22. }
  23. ],
  24. messages: {
  25. expectedTestCons: "Expected newline between test and consequent of ternary expression.",
  26. expectedConsAlt: "Expected newline between consequent and alternate of ternary expression.",
  27. unexpectedTestCons: "Unexpected newline between test and consequent of ternary expression.",
  28. unexpectedConsAlt: "Unexpected newline between consequent and alternate of ternary expression."
  29. }
  30. },
  31. create(context) {
  32. const option = context.options[0];
  33. const multiline = option !== "never";
  34. const allowSingleLine = option === "always-multiline";
  35. //--------------------------------------------------------------------------
  36. // Helpers
  37. //--------------------------------------------------------------------------
  38. /**
  39. * Tests whether node is preceded by supplied tokens
  40. * @param {ASTNode} node node to check
  41. * @param {ASTNode} parentNode parent of node to report
  42. * @param {boolean} expected whether newline was expected or not
  43. * @returns {void}
  44. * @private
  45. */
  46. function reportError(node, parentNode, expected) {
  47. context.report({
  48. node,
  49. messageId: `${expected ? "expected" : "unexpected"}${node === parentNode.test ? "TestCons" : "ConsAlt"}`
  50. });
  51. }
  52. //--------------------------------------------------------------------------
  53. // Public
  54. //--------------------------------------------------------------------------
  55. return {
  56. ConditionalExpression(node) {
  57. const areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(node.test, node.consequent);
  58. const areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(node.consequent, node.alternate);
  59. if (!multiline) {
  60. if (!areTestAndConsequentOnSameLine) {
  61. reportError(node.test, node, false);
  62. }
  63. if (!areConsequentAndAlternateOnSameLine) {
  64. reportError(node.consequent, node, false);
  65. }
  66. } else {
  67. if (allowSingleLine && node.loc.start.line === node.loc.end.line) {
  68. return;
  69. }
  70. if (areTestAndConsequentOnSameLine) {
  71. reportError(node.test, node, true);
  72. }
  73. if (areConsequentAndAlternateOnSameLine) {
  74. reportError(node.consequent, node, true);
  75. }
  76. }
  77. }
  78. };
  79. }
  80. };