Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ The following rules extend the rules provided by ESLint itself and apply them to
| [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: |
| [vue/no-implicit-coercion](./no-implicit-coercion.md) | Disallow shorthand type conversions in `<template>` | :wrench: | :hammer: |
| [vue/no-irregular-whitespace](./no-irregular-whitespace.md) | disallow irregular whitespace in `.vue` files | | :warning: |
| [vue/no-loss-of-precision](./no-loss-of-precision.md) | Disallow literal numbers that lose precision in `<template>` | | :warning: |
| [vue/no-restricted-syntax](./no-restricted-syntax.md) | Disallow specified syntax in `<template>` | | :hammer: |
Expand Down
32 changes: 32 additions & 0 deletions docs/rules/no-implicit-coercion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/no-implicit-coercion
description: Disallow shorthand type conversions in `<template>`
since: v9.33.0
---

# vue/no-implicit-coercion

> Disallow shorthand type conversions in `<template>`

- :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 [no-implicit-coercion] rule but it applies to the expressions in `<template>`.

## :books: Further Reading

- [no-implicit-coercion]

[no-implicit-coercion]: https://eslint.org/docs/rules/no-implicit-coercion

## :rocket: Version

This rule was introduced in eslint-plugin-vue v9.33.0

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-implicit-coercion.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-implicit-coercion.js)

<sup>Taken with ❤️ [from ESLint core](https://eslint.org/docs/latest/rules/no-implicit-coercion)</sup>
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
'no-export-in-script-setup': require('./rules/no-export-in-script-setup'),
'no-expose-after-await': require('./rules/no-expose-after-await'),
'no-extra-parens': require('./rules/no-extra-parens'),
'no-implicit-coercion': require('./rules/no-implicit-coercion'),
'no-invalid-model-keys': require('./rules/no-invalid-model-keys'),
'no-irregular-whitespace': require('./rules/no-irregular-whitespace'),
'no-lifecycle-after-await': require('./rules/no-lifecycle-after-await'),
Expand Down Expand Up @@ -284,7 +285,7 @@
vue: require('./processor')
},
environments: {
// TODO Remove in the next major version

Check warning on line 288 in lib/index.js

View workflow job for this annotation

GitHub Actions / Lint

Unexpected 'todo' comment: 'TODO Remove in the next major version'
/** @deprecated */
'setup-compiler-macros': {
globals: {
Expand Down
12 changes: 12 additions & 0 deletions lib/rules/no-implicit-coercion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @author lozinsky <https://github.com/lozinsky>
* See LICENSE file in root directory for full license.
*/
'use strict'

const utils = require('../utils')

// eslint-disable-next-line internal/no-invalid-meta
module.exports = utils.wrapCoreRule('no-implicit-coercion', {
applyDocument: true
})
267 changes: 267 additions & 0 deletions tests/lib/rules/no-implicit-coercion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/**
* @author lozinsky <https://github.com/lozinsky>
* See LICENSE file in root directory for full license.
*/
'use strict'

const { RuleTester, ESLint } = require('../../eslint-compat')
const semver = require('semver')
const rule = require('../../../lib/rules/no-implicit-coercion')

const tester = new RuleTester({
languageOptions: {
parser: require('vue-eslint-parser'),
ecmaVersion: 2020,
sourceType: 'module'
}
})

tester.run('no-implicit-coercion', rule, {
valid: [
`<template><div :data-foo="Boolean(foo)" /></template>`,
`<template><div :data-foo="foo.indexOf('.') !== -1" /></template>`,
{
filename: 'test.vue',
code: `<template><div :data-foo="!!foo" /></template>`,
options: [
{
boolean: false
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="~foo.indexOf('.')" /></template>`,
options: [
{
boolean: false
}
]
},
`<template><div :data-foo="Number(foo)" /></template>`,
...(semver.gte(ESLint.version, '8.28.0')
? [`<template><div :data-foo="foo * 1/4" /></template>`]
: []),
{
filename: 'test.vue',
code: `<template><div :data-foo="+foo" /></template>`,
options: [
{
number: false
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="1 * foo" /></template>`,
options: [
{
number: false
}
]
},
`<template><div :data-foo="String(foo)" /></template>`,
`<template><div :data-foo="\`\${foo}\`" /></template>`,
{
filename: 'test.vue',
code: `<template><div :data-foo="'' + foo" /></template>`,
options: [
{
string: false
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="\`\` + foo" /></template>`,
options: [
{
string: false
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="!!foo" /></template>`,
options: [
{
allow: ['!!']
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="~foo.indexOf('.')" /></template>`,
options: [
{
allow: ['~']
}
]
}
],
invalid: [
{
filename: 'test.vue',
code: `<template><div :data-foo="!!foo" /></template>`,
output: `<template><div :data-foo="Boolean(foo)" /></template>`,
errors: [
{
message: semver.gte(ESLint.version, '9.0.0')
? 'Unexpected implicit coercion encountered. Use `Boolean(foo)` instead.'
: 'use `Boolean(foo)` instead.',
line: 1,
column: 27
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="~foo.indexOf('.')" /></template>`,
output: null,
errors: [
{
message: semver.gte(ESLint.version, '9.0.0')
? "Unexpected implicit coercion encountered. Use `foo.indexOf('.') !== -1` instead."
: "use `foo.indexOf('.') !== -1` instead.",
line: 1,
column: 27
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="+foo" /></template>`,
output: semver.gte(ESLint.version, '9.0.0')
? null
: `<template><div :data-foo="Number(foo)" /></template>`,
errors: [
{
message: semver.gte(ESLint.version, '9.0.0')
? 'Unexpected implicit coercion encountered. Use `Number(foo)` instead.'
: 'use `Number(foo)` instead.',
line: 1,
column: 27,
suggestions: semver.gte(ESLint.version, '9.0.0')
? [
{
messageId: 'useRecommendation',
data: { recommendation: 'Number(foo)' },
output: '<template><div :data-foo="Number(foo)" /></template>'
}
]
: []
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="1 * foo" /></template>`,
output: semver.gte(ESLint.version, '9.0.0')
? null
: `<template><div :data-foo="Number(foo)" /></template>`,
errors: [
{
message: semver.gte(ESLint.version, '9.0.0')
? 'Unexpected implicit coercion encountered. Use `Number(foo)` instead.'
: 'use `Number(foo)` instead.',
line: 1,
column: 27,
suggestions: semver.gte(ESLint.version, '9.0.0')
? [
{
messageId: 'useRecommendation',
data: { recommendation: 'Number(foo)' },
output: '<template><div :data-foo="Number(foo)" /></template>'
}
]
: []
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="'' + foo" /></template>`,
output: semver.gte(ESLint.version, '9.0.0')
? null
: `<template><div :data-foo="String(foo)" /></template>`,
errors: [
{
message: semver.gte(ESLint.version, '9.0.0')
? 'Unexpected implicit coercion encountered. Use `String(foo)` instead.'
: 'use `String(foo)` instead.',
line: 1,
column: 27,
suggestions: semver.gte(ESLint.version, '9.0.0')
? [
{
messageId: 'useRecommendation',
data: { recommendation: 'String(foo)' },
output: '<template><div :data-foo="String(foo)" /></template>'
}
]
: []
}
]
},
{
filename: 'test.vue',
code: `<template><div :data-foo="\`\` + foo" /></template>`,
output: semver.gte(ESLint.version, '9.0.0')
? null
: `<template><div :data-foo="String(foo)" /></template>`,
errors: [
{
message: semver.gte(ESLint.version, '9.0.0')
? 'Unexpected implicit coercion encountered. Use `String(foo)` instead.'
: 'use `String(foo)` instead.',
line: 1,
column: 27,
suggestions: semver.gte(ESLint.version, '9.0.0')
? [
{
messageId: 'useRecommendation',
data: { recommendation: 'String(foo)' },
output: '<template><div :data-foo="String(foo)" /></template>'
}
]
: []
}
]
},
...(semver.gte(ESLint.version, '7.24.0')
? [
{
filename: 'test.vue',
code: `<template><div :data-foo="\`\${foo}\`" /></template>`,
output: semver.gte(ESLint.version, '9.0.0')
? null
: `<template><div :data-foo="String(foo)" /></template>`,
options: [
{
disallowTemplateShorthand: true
}
],
errors: [
{
message: semver.gte(ESLint.version, '9.0.0')
? 'Unexpected implicit coercion encountered. Use `String(foo)` instead.'
: 'use `String(foo)` instead.',
line: 1,
column: 27,
suggestions: semver.gte(ESLint.version, '9.0.0')
? [
{
messageId: 'useRecommendation',
data: { recommendation: 'String(foo)' },
output:
'<template><div :data-foo="String(foo)" /></template>'
}
]
: []
}
]
}
]
: [])
]
})
Loading