Skip to content

Commit 9c49dcc

Browse files
ota-meshimichalsnik
authored andcommitted
⭐️New: Add vue/no-restricted-syntax rule (#758)
* ⭐️New: Add `vue/no-restricted-syntax` rule Close #689 * ⭐️New: Add `vue/no-restricted-syntax` rule Close #689 * fixed
1 parent 3b3fc6c commit 9c49dcc

File tree

5 files changed

+184
-0
lines changed

5 files changed

+184
-0
lines changed

docs/rules/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ For example:
144144
| [vue/eqeqeq](./eqeqeq.md) | require the use of `===` and `!==` | :wrench: |
145145
| [vue/key-spacing](./key-spacing.md) | enforce consistent spacing between keys and values in object literal properties | :wrench: |
146146
| [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name | |
147+
| [vue/no-restricted-syntax](./no-restricted-syntax.md) | disallow specified syntax | |
147148
| [vue/object-curly-spacing](./object-curly-spacing.md) | enforce consistent spacing inside braces | :wrench: |
148149
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | |
149150
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: |

docs/rules/no-restricted-syntax.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-restricted-syntax
5+
description: disallow specified syntax
6+
---
7+
# vue/no-restricted-syntax
8+
> disallow specified syntax
9+
10+
This rule is the same rule as core [no-restricted-syntax] rule but it applies to the expressions in `<template>`.
11+
12+
13+
## :wrench: Options
14+
15+
Please see [no-restricted-syntax] for detailed options.
16+
17+
You can include the AST created by [vue-eslint-parser] in the selector.
18+
To know more about certain nodes in produced AST, please go [vue-eslint-parser - AST docs].
19+
20+
### `"VElement > VExpressionContainer CallExpression"`
21+
22+
Forbids call expressions inside mustache interpolation.
23+
24+
<eslint-code-block :rules="{'vue/no-restricted-syntax': ['error', 'VElement > VExpressionContainer CallExpression']}">
25+
26+
```vue
27+
<template>
28+
<!-- ✔ GOOD -->
29+
<div> {{ foo }} </div>
30+
<div> {{ foo.bar }} </div>
31+
32+
<!-- ✘ BAD -->
33+
<div> {{ foo() }} </div>
34+
<div> {{ foo.bar() }} </div>
35+
<div> {{ foo().bar }} </div>
36+
</template>
37+
```
38+
39+
</eslint-code-block>
40+
41+
## :books: Further reading
42+
43+
- [no-restricted-syntax]
44+
- [ESTree]
45+
- [vue-eslint-parser]
46+
47+
[no-restricted-syntax]: https://eslint.org/docs/rules/no-restricted-syntax
48+
[ESTree]: https://github.com/estree/estree
49+
[vue-eslint-parser]: https://github.com/mysticatea/vue-eslint-parser
50+
[vue-eslint-parser - AST docs]: https://github.com/mysticatea/vue-eslint-parser/blob/master/docs/ast.md
51+
52+
## :mag: Implementation
53+
54+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-restricted-syntax.js)
55+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-restricted-syntax.js)

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ module.exports = {
3333
'no-multi-spaces': require('./rules/no-multi-spaces'),
3434
'no-parsing-error': require('./rules/no-parsing-error'),
3535
'no-reserved-keys': require('./rules/no-reserved-keys'),
36+
'no-restricted-syntax': require('./rules/no-restricted-syntax'),
3637
'no-shared-component-data': require('./rules/no-shared-component-data'),
3738
'no-side-effects-in-computed-properties': require('./rules/no-side-effects-in-computed-properties'),
3839
'no-spaces-around-equal-signs-in-attribute': require('./rules/no-spaces-around-equal-signs-in-attribute'),

lib/rules/no-restricted-syntax.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @author Yosuke Ota
3+
*/
4+
'use strict'
5+
6+
const { wrapCoreRule } = require('../utils')
7+
8+
// eslint-disable-next-line
9+
module.exports = wrapCoreRule(require('eslint/lib/rules/no-restricted-syntax'))
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* @author Yosuke Ota
3+
*/
4+
'use strict'
5+
6+
const RuleTester = require('eslint').RuleTester
7+
const rule = require('../../../lib/rules/no-restricted-syntax')
8+
9+
const tester = new RuleTester({
10+
parser: 'vue-eslint-parser',
11+
parserOptions: { ecmaVersion: 2015 }
12+
})
13+
14+
tester.run('no-restricted-syntax', rule, {
15+
valid: [
16+
{
17+
code: `
18+
<template>
19+
<input :value="value">
20+
</template>`,
21+
options: [
22+
{
23+
'selector': 'CallExpression',
24+
'message': 'Call expressions are not allowed.'
25+
}
26+
]
27+
}
28+
],
29+
invalid: [
30+
{
31+
code: `
32+
<template>
33+
<input :value="value()">
34+
</template>`,
35+
options: [
36+
{
37+
'selector': 'CallExpression',
38+
'message': 'Call expressions are not allowed.'
39+
}
40+
],
41+
errors: [
42+
{
43+
message: 'Call expressions are not allowed.',
44+
line: 3,
45+
column: 26,
46+
endLine: 3,
47+
endColumn: 33
48+
}
49+
]
50+
},
51+
52+
// Forbids call expressions inside mustache interpolation.
53+
{
54+
code: `
55+
<template>
56+
<div> {{ foo() }} </div>
57+
<div> {{ foo.bar() }} </div>
58+
<div> {{ foo().bar }} </div>
59+
</template>`,
60+
options: [
61+
{
62+
'selector': 'VElement > VExpressionContainer CallExpression',
63+
'message': 'Call expressions are not allowed inside mustache interpolation.'
64+
}
65+
],
66+
errors: [
67+
{
68+
message: 'Call expressions are not allowed inside mustache interpolation.',
69+
line: 3,
70+
column: 20,
71+
endLine: 3,
72+
endColumn: 25
73+
},
74+
{
75+
message: 'Call expressions are not allowed inside mustache interpolation.',
76+
line: 4,
77+
column: 20,
78+
endLine: 4,
79+
endColumn: 29
80+
},
81+
{
82+
message: 'Call expressions are not allowed inside mustache interpolation.',
83+
line: 5,
84+
column: 20,
85+
endLine: 5,
86+
endColumn: 25
87+
}
88+
]
89+
},
90+
91+
// Sample source code on issue 689
92+
{
93+
code: `
94+
<template>
95+
<div :foo="$gettext(\`bar\`)">{{$gettext(\`bar\`)}}</div>
96+
</template>`,
97+
options: [
98+
"CallExpression[callee.type='Identifier'][callee.name='$gettext'] TemplateLiteral"
99+
],
100+
errors: [
101+
{
102+
message: 'Using \'CallExpression[callee.type=\'Identifier\'][callee.name=\'$gettext\'] TemplateLiteral\' is not allowed.',
103+
line: 3,
104+
column: 29,
105+
endLine: 3,
106+
endColumn: 34
107+
},
108+
{
109+
message: 'Using \'CallExpression[callee.type=\'Identifier\'][callee.name=\'$gettext\'] TemplateLiteral\' is not allowed.',
110+
line: 3,
111+
column: 48,
112+
endLine: 3,
113+
endColumn: 53
114+
}
115+
]
116+
}
117+
]
118+
})

0 commit comments

Comments
 (0)