Skip to content

Commit ea74835

Browse files
committed
feat: add no-import-compiler-macros rule
1 parent 827ab4b commit ea74835

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* @author Wayne Zhang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const COMPILER_MACROS = new Set([
8+
'defineProps',
9+
'defineEmits',
10+
'defineExpose',
11+
'withDefaults'
12+
])
13+
14+
const VUE_MODULES = new Set(['@vue/runtime-core', '@vue/runtime-dom', 'vue'])
15+
16+
/**
17+
* @param {Token} node
18+
*/
19+
function isComma(node) {
20+
return node.type === 'Punctuator' && node.value === ','
21+
}
22+
23+
/**
24+
* @param {Token} node
25+
*/
26+
function isLeftCurlyBrace(node) {
27+
return node.type === 'Punctuator' && node.value === '{'
28+
}
29+
30+
module.exports = {
31+
meta: {
32+
type: 'problem',
33+
docs: {
34+
description: 'disallow importing vue compiler macros',
35+
categories: undefined,
36+
url: 'https://eslint.vuejs.org/rules/no-import-compiler-macros.html'
37+
},
38+
fixable: 'code',
39+
schema: [],
40+
messages: {
41+
noImportCompilerMacros:
42+
"'{{name}}' is a compiler macro and no longer needs to be imported from '{{source}}'."
43+
}
44+
},
45+
/**
46+
* @param {RuleContext} context
47+
* @returns {RuleListener}
48+
*/
49+
create(context) {
50+
const sourceCode = context.getSourceCode()
51+
52+
return {
53+
ImportDeclaration(node) {
54+
if (node.specifiers.length === 0) return
55+
56+
if (VUE_MODULES.has(node.source.value)) {
57+
for (const specifier of node.specifiers) {
58+
if (
59+
specifier.type === 'ImportSpecifier' &&
60+
COMPILER_MACROS.has(specifier.imported.name)
61+
) {
62+
context.report({
63+
node: specifier,
64+
messageId: 'noImportCompilerMacros',
65+
data: {
66+
name: specifier.imported.name,
67+
source: node.source.value
68+
},
69+
fix: (fixer) => {
70+
const tokenAfter = sourceCode.getTokenAfter(specifier)
71+
const tokenBefore = sourceCode.getTokenBefore(specifier)
72+
73+
const hasCommaAfter = isComma(tokenAfter)
74+
const isFirstSpecifier = isLeftCurlyBrace(tokenBefore)
75+
76+
const codeStart = hasCommaAfter
77+
? tokenBefore.range[1]
78+
: isFirstSpecifier
79+
? specifier.range[0]
80+
: tokenBefore.range[0]
81+
const codeEnd = hasCommaAfter
82+
? tokenAfter.range[1]
83+
: specifier.range[1]
84+
85+
return fixer.removeRange([codeStart, codeEnd])
86+
}
87+
})
88+
}
89+
}
90+
}
91+
}
92+
}
93+
}
94+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/**
2+
* @author Wayne Zhang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const RuleTester = require('../../eslint-compat').RuleTester
8+
const rule = require('../../../lib/rules/no-import-compiler-macros')
9+
10+
const tester = new RuleTester({
11+
languageOptions: {
12+
parser: require('vue-eslint-parser'),
13+
ecmaVersion: 2020,
14+
sourceType: 'module'
15+
}
16+
})
17+
18+
tester.run('no-import-compiler-macros', rule, {
19+
valid: [
20+
{
21+
filename: 'test.vue',
22+
code: `
23+
<script setup>
24+
import { ref } from 'vue'
25+
import { someFunction } from '@vue/runtime-core'
26+
</script>
27+
`
28+
},
29+
{
30+
filename: 'test.vue',
31+
code: `
32+
<script>
33+
import { defineProps } from 'some-other-package'
34+
</script>
35+
`
36+
}
37+
],
38+
invalid: [
39+
{
40+
filename: 'test.vue',
41+
code: `
42+
<script setup>
43+
import { computed, defineProps } from 'vue'
44+
import { defineEmits, ref, withDefaults } from '@vue/runtime-core'
45+
import { defineExpose, watch } from '@vue/runtime-dom'
46+
</script>
47+
`,
48+
output: `
49+
<script setup>
50+
import { computed } from 'vue'
51+
import { ref } from '@vue/runtime-core'
52+
import { watch } from '@vue/runtime-dom'
53+
</script>
54+
`,
55+
errors: [
56+
{
57+
messageId: 'noImportCompilerMacros',
58+
data: {
59+
name: 'defineProps',
60+
source: 'vue'
61+
},
62+
line: 3,
63+
column: 26
64+
},
65+
{
66+
messageId: 'noImportCompilerMacros',
67+
data: {
68+
name: 'defineEmits',
69+
source: '@vue/runtime-core'
70+
},
71+
line: 4,
72+
column: 16
73+
},
74+
{
75+
messageId: 'noImportCompilerMacros',
76+
data: {
77+
name: 'withDefaults',
78+
source: '@vue/runtime-core'
79+
},
80+
line: 4,
81+
column: 34
82+
},
83+
{
84+
messageId: 'noImportCompilerMacros',
85+
data: {
86+
name: 'defineExpose',
87+
source: '@vue/runtime-dom'
88+
},
89+
line: 5,
90+
column: 16
91+
}
92+
]
93+
},
94+
{
95+
filename: 'test.vue',
96+
code: `
97+
<script setup>
98+
import { defineProps, withDefaults, ref } from 'vue'
99+
</script>
100+
`,
101+
output: `
102+
<script setup>
103+
import { withDefaults, ref } from 'vue'
104+
</script>
105+
`,
106+
errors: [
107+
{
108+
messageId: 'noImportCompilerMacros',
109+
data: {
110+
name: 'defineProps',
111+
source: 'vue'
112+
},
113+
line: 3,
114+
column: 16
115+
},
116+
{
117+
messageId: 'noImportCompilerMacros',
118+
data: {
119+
name: 'withDefaults',
120+
source: 'vue'
121+
},
122+
line: 3,
123+
column: 29
124+
}
125+
]
126+
}
127+
]
128+
})

0 commit comments

Comments
 (0)