Skip to content

Commit

Permalink
Fix false positives for <script setup> in `vue/no-lifecycle-after-a…
Browse files Browse the repository at this point in the history
…wait`, `vue/no-watch-after-await`, `vue/no-restricted-call-after-await` rules. (#1569)
  • Loading branch information
ota-meshi committed Jul 17, 2021
1 parent cac3beb commit 9dc78d0
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 159 deletions.
47 changes: 11 additions & 36 deletions lib/rules/no-lifecycle-after-await.js
Expand Up @@ -48,27 +48,19 @@ module.exports = {
/**
* @typedef {object} ScopeStack
* @property {ScopeStack | null} upper
* @property {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression | Program} scopeNode
* @property {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression} scopeNode
*/
/** @type {Set<ESNode>} */
const lifecycleHookCallNodes = new Set()
/** @type {Map<FunctionDeclaration | FunctionExpression | ArrowFunctionExpression | Program, SetupScopeData>} */
/** @type {Map<FunctionDeclaration | FunctionExpression | ArrowFunctionExpression, SetupScopeData>} */
const setupScopes = new Map()

/** @type {ScopeStack | null} */
let scopeStack = null

return utils.compositingVisitors(
{
/**
* @param {Program} node
*/
Program(node) {
scopeStack = {
upper: scopeStack,
scopeNode: node
}

Program() {
const tracker = new ReferenceTracker(context.getScope())
const traceMap = {
/** @type {TraceMap} */
Expand All @@ -85,6 +77,14 @@ module.exports = {
for (const { node } of tracker.iterateEsmReferences(traceMap)) {
lifecycleHookCallNodes.add(node)
}
}
},
utils.defineVueVisitor(context, {
onSetupFunctionEnter(node) {
setupScopes.set(node, {
afterAwait: false,
range: node.range
})
},
/**
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
Expand Down Expand Up @@ -133,31 +133,6 @@ module.exports = {
messageId: 'forbidden'
})
}
}
},
(() => {
const scriptSetup = utils.getScriptSetupElement(context)
if (!scriptSetup) {
return {}
}
return {
/**
* @param {Program} node
*/
Program(node) {
setupScopes.set(node, {
afterAwait: false,
range: scriptSetup.range
})
}
}
})(),
utils.defineVueVisitor(context, {
onSetupFunctionEnter(node) {
setupScopes.set(node, {
afterAwait: false,
range: node.range
})
},
onSetupFunctionExit(node) {
setupScopes.delete(node)
Expand Down
42 changes: 10 additions & 32 deletions lib/rules/no-restricted-call-after-await.js
Expand Up @@ -62,13 +62,13 @@ module.exports = {

/** @type {Map<ESNode, string>} */
const restrictedCallNodes = new Map()
/** @type {Map<FunctionExpression | ArrowFunctionExpression | FunctionDeclaration | Program, SetupScopeData>} */
/** @type {Map<FunctionExpression | ArrowFunctionExpression | FunctionDeclaration, SetupScopeData>} */
const setupScopes = new Map()

/**x
* @typedef {object} ScopeStack
* @property {ScopeStack | null} upper
* @property {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration | Program} scopeNode
* @property {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration} scopeNode
*/
/** @type {ScopeStack | null} */
let scopeStack = null
Expand Down Expand Up @@ -142,11 +142,6 @@ module.exports = {
{
/** @param {Program} node */
Program(node) {
scopeStack = {
upper: scopeStack,
scopeNode: node
}

const tracker = new ReferenceTracker(context.getScope())

for (const option of context.options) {
Expand Down Expand Up @@ -181,6 +176,14 @@ module.exports = {
}
}
}
}
},
utils.defineVueVisitor(context, {
onSetupFunctionEnter(node) {
setupScopes.set(node, {
afterAwait: false,
range: node.range
})
},
/** @param {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration} node */
':function'(node) {
Expand Down Expand Up @@ -225,31 +228,6 @@ module.exports = {
data: { message }
})
}
}
},
(() => {
const scriptSetup = utils.getScriptSetupElement(context)
if (!scriptSetup) {
return {}
}
return {
/**
* @param {Program} node
*/
Program(node) {
setupScopes.set(node, {
afterAwait: false,
range: scriptSetup.range
})
}
}
})(),
utils.defineVueVisitor(context, {
onSetupFunctionEnter(node) {
setupScopes.set(node, {
afterAwait: false,
range: node.range
})
},
onSetupFunctionExit(node) {
setupScopes.delete(node)
Expand Down
45 changes: 11 additions & 34 deletions lib/rules/no-watch-after-await.js
Expand Up @@ -62,26 +62,20 @@ module.exports = {
* @property {boolean} afterAwait
* @property {[number,number]} range
*/
/** @type {Map<FunctionExpression | ArrowFunctionExpression | FunctionDeclaration | Program, SetupScopeData>} */
/** @type {Map<FunctionExpression | ArrowFunctionExpression | FunctionDeclaration, SetupScopeData>} */
const setupScopes = new Map()

/**
* @typedef {object} ScopeStack
* @property {ScopeStack | null} upper
* @property {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration | Program} scopeNode
* @property {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration} scopeNode
*/
/** @type {ScopeStack | null} */
let scopeStack = null

return utils.compositingVisitors(
{
/** @param {Program} node */
Program(node) {
scopeStack = {
upper: scopeStack,
scopeNode: node
}

Program() {
const tracker = new ReferenceTracker(context.getScope())
const traceMap = {
vue: {
Expand All @@ -98,6 +92,14 @@ module.exports = {
for (const { node } of tracker.iterateEsmReferences(traceMap)) {
watchCallNodes.add(node)
}
}
},
utils.defineVueVisitor(context, {
onSetupFunctionEnter(node) {
setupScopes.set(node, {
afterAwait: false,
range: node.range
})
},
/** @param {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration} node */
':function'(node) {
Expand Down Expand Up @@ -140,31 +142,6 @@ module.exports = {
messageId: 'forbidden'
})
}
}
},
(() => {
const scriptSetup = utils.getScriptSetupElement(context)
if (!scriptSetup) {
return {}
}
return {
/**
* @param {Program} node
*/
Program(node) {
setupScopes.set(node, {
afterAwait: false,
range: scriptSetup.range
})
}
}
})(),
utils.defineVueVisitor(context, {
onSetupFunctionEnter(node) {
setupScopes.set(node, {
afterAwait: false,
range: node.range
})
},
onSetupFunctionExit(node) {
setupScopes.delete(node)
Expand Down
30 changes: 12 additions & 18 deletions tests/lib/rules/no-lifecycle-after-await.js
Expand Up @@ -139,6 +139,18 @@ tester.run('no-lifecycle-after-await', rule, {
<script>
import {onMounted} from 'vue'
await doSomething()
onMounted(() => { /* ... */ }) // not error
</script>
`,
parserOptions: { ecmaVersion: 2022 }
},
{
filename: 'test.vue',
code: `
<script setup>
import {onMounted} from 'vue'
await doSomething()
onMounted(() => { /* ... */ }) // not error
</script>
`,
Expand Down Expand Up @@ -261,24 +273,6 @@ tester.run('no-lifecycle-after-await', rule, {
messageId: 'forbidden'
}
]
},
{
filename: 'test.vue',
code: `
<script setup>
import {onMounted} from 'vue'
await doSomething()
onMounted(() => { /* ... */ }) // error
</script>
`,
parserOptions: { ecmaVersion: 2022 },
errors: [
{
messageId: 'forbidden',
line: 6
}
]
}
]
})
31 changes: 12 additions & 19 deletions tests/lib/rules/no-restricted-call-after-await.js
Expand Up @@ -137,6 +137,18 @@ tester.run('no-restricted-call-after-await', rule, {
`,
options: [{ module: 'vue-i18n', path: 'useI18n' }],
parserOptions: { ecmaVersion: 2022 }
},
{
filename: 'test.vue',
code: `
<script setup>
import {useI18n} from 'vue-i18n'
await doSomething()
useI18n()
</script>
`,
parserOptions: { ecmaVersion: 2022 },
options: [{ module: 'vue-i18n', path: 'useI18n' }]
}
],
invalid: [
Expand Down Expand Up @@ -389,25 +401,6 @@ tester.run('no-restricted-call-after-await', rule, {
line: 7
}
]
},
{
filename: 'test.vue',
code: `
<script setup>
import {useI18n} from 'vue-i18n'
await doSomething()
useI18n()
</script>
`,
parserOptions: { ecmaVersion: 2022 },
options: [{ module: 'vue-i18n', path: 'useI18n' }],
errors: [
{
message:
'The `import("vue-i18n").useI18n` after `await` expression are forbidden.',
line: 5
}
]
}
]
})
34 changes: 14 additions & 20 deletions tests/lib/rules/no-watch-after-await.js
Expand Up @@ -155,6 +155,20 @@ tester.run('no-watch-after-await', rule, {
</script>
`,
parserOptions: { ecmaVersion: 2022 }
},
{
filename: 'test.vue',
code: `
<script setup>
import {watch} from 'vue'
watch(foo, () => { /* ... */ })
await doSomething()
watch(foo, () => { /* ... */ })
</script>
`,
parserOptions: { ecmaVersion: 2022 }
}
],
invalid: [
Expand Down Expand Up @@ -236,26 +250,6 @@ tester.run('no-watch-after-await', rule, {
line: 12
}
]
},
{
filename: 'test.vue',
code: `
<script setup>
import {watch} from 'vue'
watch(foo, () => { /* ... */ })
await doSomething()
watch(foo, () => { /* ... */ })
</script>
`,
parserOptions: { ecmaVersion: 2022 },
errors: [
{
message: 'The `watch` after `await` expression are forbidden.',
line: 8
}
]
}
]
})

0 comments on commit 9dc78d0

Please sign in to comment.