Repository: vuejs/eslint-plugin-vue
Pull request #1996 (2022-09-28 13:55:42)

Create `vue/multiline-ternary` extension rule
Wrap multiline ternary rule for vue.

Not sure about the indenting, maybe it is not an issue and would be handled by other rules. Looks strange.

FloEdelmann: Could you please fix the lint issues? Also, there are some tests failing in ESLint v6, @ota-meshi maybe you can help how to skip those tests there?
dev1437: Not sure why the test fail in eslint v6 but run fine locally, but lint is okay now
ota-meshi: It seems that the multiline-ternary rule did not previously support autofix.

I think it is necessary to check the version of eslint and ignore the `output` check (set `null`).
I think the following test case will be helpful.
https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-loss-of-precision.js#L20
FloEdelmann: Please also add the new rule to https://deploy-preview-1996--eslint-plugin-vue.netlify.app/rules/#extension-rules.

It seems that this doesn't work automatically when running `npm run update`.
ota-meshi: https://github.com/vuejs/eslint-plugin-vue/pull/1996#discussion_r985069682

Patch:
diff --git a/docs/rules/README.md b/docs/rules/README.md
index 780b10cb..19c2565e 100644
--- a/docs/rules/README.md
+++ b/docs/rules/README.md
@@ -292,6 +292,7 @@ The following rules extend the rules provided by ESLint itself and apply them to
 | [vue/key-spacing](./key-spacing.md) | Enforce consistent spacing between keys and values in object literal properties in `<template>` | :wrench: | :lipstick: |
 | [vue/keyword-spacing](./keyword-spacing.md) | Enforce consistent spacing before and after keywords in `<template>` | :wrench: | :lipstick: |
 | [vue/max-len](./max-len.md) | enforce a maximum line length in `.vue` files |  | :lipstick: |
+| [vue/multiline-ternary](./multiline-ternary.md) | Enforce newlines between operands of ternary expressions in `<template>` | :wrench: | :lipstick: |
 | [vue/no-constant-condition](./no-constant-condition.md) | Disallow constant expressions in conditions in `<template>` |  | :warning: |
 | [vue/no-empty-pattern](./no-empty-pattern.md) | Disallow empty destructuring patterns in `<template>` |  | :warning: |
 | [vue/no-extra-parens](./no-extra-parens.md) | Disallow unnecessary parentheses in `<template>` | :wrench: | :lipstick: |
diff --git a/docs/rules/multiline-ternary.md b/docs/rules/multiline-ternary.md
new file mode 100644
index 00000000..cc36f7da
--- /dev/null
+++ b/docs/rules/multiline-ternary.md
@@ -0,0 +1,59 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/multiline-ternary
+description: Enforce newlines between operands of ternary expressions in `<template>`
+---
+# vue/multiline-ternary
+
+> Enforce newlines between operands of ternary expressions in `<template>`
+
+- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
+- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
+
+This rule is the same rule as core [multiline-ternary] rule but it applies to the expressions in `<template>` and `<style>`.
+
+## :book: Rule Details
+
+<eslint-code-block fix :rules="{'vue/multiline-ternary': ['error']}">
+
+```vue
+<template>
+  <div>
+    <!-- ✓ GOOD -->
+    <div :class="isEnabled
+      ? 'check'
+      : 'stop'" />
+
+    <!-- ✗ BAD -->
+    <div :class="isEnabled ? 'check' : 'stop'" />
+  </div>
+</template>
+
+<style>
+div {
+  /* ✓ GOOD */
+  color: v-bind('myFlag
+    ? foo
+    : bar');
+
+  /* ✗ BAD */
+  color: v-bind('myFlag ? foo : bar');
+}
+</style>
+```
+
+</eslint-code-block>
+
+## :books: Further Reading
+
+- [multiline-ternary]
+
+[multiline-ternary]: https://eslint.org/docs/rules/multiline-ternary
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/multiline-ternary.js)
+- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/multiline-ternary.js)
+
+<sup>Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/multiline-ternary)</sup>
diff --git a/lib/configs/no-layout-rules.js b/lib/configs/no-layout-rules.js
index 6b15833c..58e62b60 100644
--- a/lib/configs/no-layout-rules.js
+++ b/lib/configs/no-layout-rules.js
@@ -31,6 +31,7 @@ module.exports = {
     'vue/max-attributes-per-line': 'off',
     'vue/max-len': 'off',
     'vue/multiline-html-element-content-newline': 'off',
+    'vue/multiline-ternary': 'off',
     'vue/mustache-interpolation-spacing': 'off',
     'vue/new-line-between-multi-line-property': 'off',
     'vue/no-extra-parens': 'off',
diff --git a/lib/index.js b/lib/index.js
index e7dcd5be..645669c4 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -54,6 +54,7 @@ module.exports = {
     'max-len': require('./rules/max-len'),
     'multi-word-component-names': require('./rules/multi-word-component-names'),
     'multiline-html-element-content-newline': require('./rules/multiline-html-element-content-newline'),
+    'multiline-ternary': require('./rules/multiline-ternary'),
     'mustache-interpolation-spacing': require('./rules/mustache-interpolation-spacing'),
     'new-line-between-multi-line-property': require('./rules/new-line-between-multi-line-property'),
     'next-tick-style': require('./rules/next-tick-style'),
diff --git a/lib/rules/multiline-ternary.js b/lib/rules/multiline-ternary.js
new file mode 100644
index 00000000..718ef8f0
--- /dev/null
+++ b/lib/rules/multiline-ternary.js
@@ -0,0 +1,17 @@
+/**
+ * @author dev1437
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const { wrapCoreRule } = require('../utils')
+
+// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
+module.exports = wrapCoreRule('multiline-ternary', {
+  skipDynamicArguments: true,
+  applyDocument: true
+})


Test patch:
diff --git a/tests/lib/rules/multiline-ternary.js b/tests/lib/rules/multiline-ternary.js
new file mode 100644
index 00000000..2922f0e6
--- /dev/null
+++ b/tests/lib/rules/multiline-ternary.js
@@ -0,0 +1,297 @@
+/**
+ * @author dev1437
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const { RuleTester, ESLint } = require('../../eslint-compat')
+const rule = require('../../../lib/rules/multiline-ternary')
+const semver = require('semver')
+
+const tester = new RuleTester({
+  parser: require.resolve('vue-eslint-parser'),
+  parserOptions: {
+    ecmaVersion: 2020,
+    sourceType: 'module'
+  }
+})
+
+tester.run('multiline-ternary', rule, {
+  valid: [
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="{
+          'test': someReallyLongCondition ?
+            aVeryLongOutput :
+            thisCantFitOnASingleLine
+        }">
+        </div>
+      </template>
+      `
+    },
+    {
+      // doesn't check ternary statements in <script> block
+      filename: 'test.vue',
+      code: `
+      <script>
+        let test = someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine
+      </script>
+      `
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="{
+          'test': someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine
+        }">
+        </div>
+      </template>
+      `,
+      options: ['never']
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+          <div class="test">
+          </div>
+      </template>
+      <style>
+        .test {
+            color: v-bind('someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine')
+        }
+      </style>
+      `,
+      options: ['never']
+    }
+  ],
+  invalid: [
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <div :class="{
+            'test': someReallyLongCondition ?
+              aVeryLongOutput : thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `,
+      output: semver.gte(ESLint.version, '7.1.0')
+        ? `
+        <template>
+          <div :class="{
+            'test': someReallyLongCondition ?
+              aVeryLongOutput
+: thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `
+        : null,
+      errors: [
+        {
+          message:
+            'Expected newline between consequent and alternate of ternary expression.',
+          line: 5,
+          column: 15
+        }
+      ],
+      options: ['always-multiline']
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <div :class="{
+            'test': someReallyLongCondition ?
+              aVeryLongOutput : thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `,
+      output: semver.gte(ESLint.version, '7.1.0')
+        ? `
+        <template>
+          <div :class="{
+            'test': someReallyLongCondition ?aVeryLongOutput : thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `
+        : null,
+      errors: [
+        {
+          message:
+            'Unexpected newline between test and consequent of ternary expression.',
+          line: 4,
+          column: 21
+        }
+      ],
+      options: ['never']
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <div :class="{
+            'test': someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `,
+      output: semver.gte(ESLint.version, '7.1.0')
+        ? `
+        <template>
+          <div :class="{
+            'test': someReallyLongCondition
+? aVeryLongOutput
+: thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `
+        : null,
+      errors: [
+        {
+          message:
+            'Expected newline between test and consequent of ternary expression.',
+          line: 4,
+          column: 21
+        },
+        {
+          message:
+            'Expected newline between consequent and alternate of ternary expression.',
+          line: 4,
+          column: 47
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <div :style="{
+            'test': someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `,
+      output: semver.gte(ESLint.version, '7.1.0')
+        ? `
+        <template>
+          <div :style="{
+            'test': someReallyLongCondition
+? aVeryLongOutput
+: thisCantFitOnASingleLine
+          }">
+          </div>
+        </template>
+        `
+        : null,
+      errors: [
+        {
+          message:
+            'Expected newline between test and consequent of ternary expression.',
+          line: 4,
+          column: 21
+        },
+        {
+          message:
+            'Expected newline between consequent and alternate of ternary expression.',
+          line: 4,
+          column: 47
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <div class="test">
+          </div>
+        </template>
+        <style>
+          .test {
+              color: v-bind('someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine')
+          }
+        </style>
+        `,
+      output: semver.gte(ESLint.version, '7.1.0')
+        ? `
+        <template>
+          <div class="test">
+          </div>
+        </template>
+        <style>
+          .test {
+              color: v-bind('someReallyLongCondition
+? aVeryLongOutput
+: thisCantFitOnASingleLine')
+          }
+        </style>
+        `
+        : null,
+      errors: [
+        {
+          message:
+            'Expected newline between test and consequent of ternary expression.',
+          line: 8,
+          column: 30
+        },
+        {
+          message:
+            'Expected newline between consequent and alternate of ternary expression.',
+          line: 8,
+          column: 56
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="{
+          'test': someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine
+        }">
+        </div>
+      </template>
+      <script>
+        let test = someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine
+      </script>
+      `,
+      output: semver.gte(ESLint.version, '7.1.0')
+        ? `
+      <template>
+        <div :class="{
+          'test': someReallyLongCondition
+? aVeryLongOutput
+: thisCantFitOnASingleLine
+        }">
+        </div>
+      </template>
+      <script>
+        let test = someReallyLongCondition ? aVeryLongOutput : thisCantFitOnASingleLine
+      </script>
+      `
+        : null,
+      errors: [
+        {
+          message:
+            'Expected newline between test and consequent of ternary expression.',
+          line: 4,
+          column: 19
+        },
+        {
+          message:
+            'Expected newline between consequent and alternate of ternary expression.',
+          line: 4,
+          column: 45
+        }
+      ]
+    }
+  ]
+})