Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7aaba4d

Browse files
waynzhCopilot
andauthored
feat: Object.assign detection to mutation rules (#2929)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 79d6a31 commit 7aaba4d

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed

‎.changeset/hot-beers-help.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-vue': minor
3+
---
4+
5+
Changed `vue/no-mutating-props` and `vue/no-side-effects-in-computed-properties` rules to detect `Object.assign` mutations

‎lib/utils/index.js‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,26 @@ module.exports = {
20682068
return false
20692069
},
20702070

2071+
/**
2072+
* Check if a call expression is Object.assign with the given node as first argument
2073+
* @param {CallExpression} callExpr
2074+
* @param {ASTNode} targetNode
2075+
* @returns {boolean}
2076+
*/
2077+
isObjectAssignCall(callExpr, targetNode) {
2078+
const { callee, arguments: args } = callExpr
2079+
2080+
return (
2081+
args.length > 0 &&
2082+
args[0] === targetNode &&
2083+
callee?.type === 'MemberExpression' &&
2084+
callee.object?.type === 'Identifier' &&
2085+
callee.object.name === 'Object' &&
2086+
callee.property?.type === 'Identifier' &&
2087+
callee.property.name === 'assign'
2088+
)
2089+
},
2090+
20712091
/**
20722092
* @param {MemberExpression|Identifier} props
20732093
* @returns { { kind: 'assignment' | 'update' | 'call' , node: ESNode, pathNodes: MemberExpression[] } | null }
@@ -2128,6 +2148,14 @@ module.exports = {
21282148
}
21292149
}
21302150
}
2151+
if (this.isObjectAssignCall(target, node)) {
2152+
// Object.assign(xxx, {})
2153+
return {
2154+
kind: 'call',
2155+
node: target,
2156+
pathNodes
2157+
}
2158+
}
21312159
break
21322160
}
21332161
case 'MemberExpression': {

‎tests/lib/rules/no-mutating-props.js‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,22 @@ ruleTester.run('no-mutating-props', rule, {
413413
const foo = ref('')
414414
</script>
415415
`
416+
},
417+
{
418+
// Object.assign not mutating the prop
419+
filename: 'test.vue',
420+
code: `
421+
<script>
422+
export default {
423+
props: ['data'],
424+
methods: {
425+
update() {
426+
return Object.assign({}, this.data, { extra: 'value' })
427+
}
428+
}
429+
}
430+
</script>
431+
`
416432
}
417433
],
418434

@@ -1420,6 +1436,31 @@ ruleTester.run('no-mutating-props', rule, {
14201436
endColumn: 21
14211437
}
14221438
]
1439+
},
1440+
{
1441+
// Object.assign mutating the prop as first argument
1442+
filename: 'test.vue',
1443+
code: `
1444+
<script>
1445+
export default {
1446+
props: ['data'],
1447+
methods: {
1448+
update() {
1449+
return Object.assign(this.data, { extra: 'value' })
1450+
}
1451+
}
1452+
}
1453+
</script>
1454+
`,
1455+
errors: [
1456+
{
1457+
message: 'Unexpected mutation of "data" prop.',
1458+
line: 7,
1459+
column: 24,
1460+
endLine: 7,
1461+
endColumn: 68
1462+
}
1463+
]
14231464
}
14241465
]
14251466
})

‎tests/lib/rules/no-side-effects-in-computed-properties.js‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, {
259259
})
260260
const test18 = computed(() => (console.log('a'), true))
261261
const test19 = computed(() => utils.reverse(foo.array))
262+
const test20 = computed(() => Object.assign({}, foo.data, { extra: 'value' }))
262263
}
263264
}
264265
</script>`
@@ -889,6 +890,54 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, {
889890
endColumn: 59
890891
}
891892
]
893+
},
894+
{
895+
// Object.assign mutating the prop as first argument in computed properties
896+
filename: 'test.vue',
897+
code: `
898+
<script>
899+
import {ref, computed} from 'vue'
900+
export default {
901+
setup() {
902+
const foo = useFoo()
903+
904+
const test1 = computed(() => Object.assign(foo.data, { extra: 'value' }))
905+
const test2 = computed(() => {
906+
return Object.assign(foo.user, foo.updates)
907+
})
908+
const test3 = computed({
909+
get() {
910+
Object.assign(foo.settings, { theme: 'dark' })
911+
return foo.settings
912+
}
913+
})
914+
}
915+
}
916+
</script>
917+
`,
918+
errors: [
919+
{
920+
message: 'Unexpected side effect in computed function.',
921+
line: 8,
922+
column: 40,
923+
endLine: 8,
924+
endColumn: 83
925+
},
926+
{
927+
message: 'Unexpected side effect in computed function.',
928+
line: 10,
929+
column: 20,
930+
endLine: 10,
931+
endColumn: 56
932+
},
933+
{
934+
message: 'Unexpected side effect in computed function.',
935+
line: 14,
936+
column: 15,
937+
endLine: 14,
938+
endColumn: 61
939+
}
940+
]
892941
}
893942
]
894943
})

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /