Skip to content

Commit 9d54bd6

Browse files
authored
Fix crash when using objectsInObjects option in vue/object-curly-spacing rule. (#1515)
1 parent 68b7502 commit 9d54bd6

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

lib/utils/index.js

+46
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ const SVG_ELEMENT_NAMES = new Set(require('./svg-elements.json'))
101101
const VOID_ELEMENT_NAMES = new Set(require('./void-elements.json'))
102102
const path = require('path')
103103
const vueEslintParser = require('vue-eslint-parser')
104+
const traverseNodes = vueEslintParser.AST.traverseNodes
104105
const { findVariable } = require('eslint-utils')
105106

106107
/**
@@ -142,11 +143,56 @@ function wrapContextToOverrideTokenMethods(context, tokenStore) {
142143
: []
143144
return tokensAndComments
144145
}
146+
147+
/** @param {number} index */
148+
function getNodeByRangeIndex(index) {
149+
const templateBody = eslintSourceCode.ast.templateBody
150+
if (!templateBody) {
151+
return eslintSourceCode.ast
152+
}
153+
154+
/** @type {ASTNode} */
155+
let result = eslintSourceCode.ast
156+
/** @type {ASTNode[]} */
157+
const skipNodes = []
158+
let breakFlag = false
159+
160+
traverseNodes(templateBody, {
161+
enterNode(node, parent) {
162+
if (breakFlag) {
163+
return
164+
}
165+
if (skipNodes[0] === parent) {
166+
skipNodes.unshift(node)
167+
return
168+
}
169+
if (node.range[0] <= index && index < node.range[1]) {
170+
result = node
171+
} else {
172+
skipNodes.unshift(node)
173+
}
174+
},
175+
leaveNode(node) {
176+
if (breakFlag) {
177+
return
178+
}
179+
if (result === node) {
180+
breakFlag = true
181+
} else if (skipNodes[0] === node) {
182+
skipNodes.shift()
183+
}
184+
}
185+
})
186+
return result
187+
}
145188
const sourceCode = new Proxy(Object.assign({}, eslintSourceCode), {
146189
get(_object, key) {
147190
if (key === 'tokensAndComments') {
148191
return getTokensAndComments()
149192
}
193+
if (key === 'getNodeByRangeIndex') {
194+
return getNodeByRangeIndex
195+
}
150196
// @ts-expect-error
151197
return key in tokenStore ? tokenStore[key] : eslintSourceCode[key]
152198
}

tests/lib/rules/object-curly-spacing.js

+60
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ tester.run('object-curly-spacing', rule, {
2626
{
2727
code: '<template><div :[{a:1}]="a" /></template>',
2828
options: ['always']
29+
},
30+
{
31+
code: `
32+
<template>
33+
<div v-bind="{foo: {bar: 'baz'} }">
34+
Hello World
35+
</div>
36+
</template>`,
37+
options: [
38+
'never',
39+
{
40+
objectsInObjects: true
41+
}
42+
]
2943
}
3044
],
3145
invalid: [
@@ -97,6 +111,52 @@ tester.run('object-curly-spacing', rule, {
97111
"A space is required after '{'.",
98112
"A space is required before '}'."
99113
]
114+
},
115+
{
116+
code: `
117+
<template>
118+
<div v-bind="{ foo: { bar: 'baz' }}">
119+
Hello World
120+
</div>
121+
</template>`,
122+
options: [
123+
'never',
124+
{
125+
objectsInObjects: true
126+
}
127+
],
128+
output: `
129+
<template>
130+
<div v-bind="{foo: {bar: 'baz'} }">
131+
Hello World
132+
</div>
133+
</template>`,
134+
errors: [
135+
"There should be no space after '{'.",
136+
"There should be no space after '{'.",
137+
"There should be no space before '}'.",
138+
"A space is required before '}'."
139+
]
140+
},
141+
{
142+
code: `
143+
<template>
144+
<div v-bind="{ foo: { bar: 'baz' }}">
145+
Hello World
146+
</div>
147+
</template>`,
148+
options: ['never'],
149+
output: `
150+
<template>
151+
<div v-bind="{foo: {bar: 'baz'}}">
152+
Hello World
153+
</div>
154+
</template>`,
155+
errors: [
156+
"There should be no space after '{'.",
157+
"There should be no space after '{'.",
158+
"There should be no space before '}'."
159+
]
100160
}
101161
]
102162
})

0 commit comments

Comments
 (0)