Skip to content

Commit 14d9938

Browse files
committed
add types to vue/sort-keys
1 parent 5c094d3 commit 14d9938

File tree

2 files changed

+88
-84
lines changed

2 files changed

+88
-84
lines changed

lib/rules/sort-keys.js

Lines changed: 86 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* @author Loren Klingman
44
* Original ESLint sort-keys by Toru Nagashima
55
*/
6-
// @ts-nocheck
76
'use strict'
87

98
// ------------------------------------------------------------------------------
@@ -121,14 +120,22 @@ module.exports = {
121120
},
122121
additionalProperties: false
123122
}
124-
]
123+
],
124+
messages: {
125+
sortKeys:
126+
"Expected object keys to be in {{natural}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'."
127+
}
125128
},
126-
/** @param {RuleContext} context */
129+
/**
130+
* @param {RuleContext} context - The rule context.
131+
* @returns {RuleListener} AST event handlers.
132+
*/
127133
create(context) {
128134
// Parse options.
129135
const options = context.options[1]
130136
const order = context.options[0] || 'asc'
131137

138+
/** @type {string[]} */
132139
const ignoreGrandchildrenOf = (options &&
133140
options.ignoreGrandchildrenOf) || [
134141
'computed',
@@ -137,127 +144,128 @@ module.exports = {
137144
'props',
138145
'watch'
139146
]
147+
/** @type {string[]} */
140148
const ignoreChildrenOf = (options && options.ignoreChildrenOf) || ['model']
141149
const insensitive = options && options.caseSensitive === false
142150
const minKeys = options && options.minKeys
143151
const natural = options && options.natural
144152
const isValidOrder =
145153
isValidOrders[order + (insensitive ? 'I' : '') + (natural ? 'N' : '')]
146154

147-
// The stack to save the previous property's name for each object literals.
148-
let stack = null
149-
150-
let errors = []
151-
const names = {}
152-
153155
/**
154-
* @param {boolean} isVue
156+
* @typedef {object} ObjectStack
157+
* @property {ObjectStack} upper
158+
* @property {string | null} prevName
159+
* @property {number} numKeys
160+
* @property {Property | null} currentProperty
161+
* @property {boolean} isVueObject
162+
* @property {boolean} withinVueObject
163+
* @property {string | null} withinVuePropName
164+
* @property {number} withinVuePropChainLevel
165+
* @property {boolean} ignore
155166
*/
156-
const reportErrors = (isVue) => {
157-
if (isVue) {
158-
errors = errors.filter((error) => {
159-
let parentIsRoot = !error.hasUpper
160-
let grandParentIsRoot = !error.grandparent
161-
let greatGrandparentIsRoot = !error.greatGrandparent
162167

163-
const stackPrevChar = stack && stack.prevChar
164-
if (stackPrevChar) {
165-
parentIsRoot = stackPrevChar === error.parent
166-
grandParentIsRoot = stackPrevChar === error.grandparent
167-
greatGrandparentIsRoot = stackPrevChar === error.greatGrandparent
168-
}
168+
/**
169+
* The stack to save the previous property's name for each object literals.
170+
* @type {ObjectStack}
171+
*/
172+
let stack
169173

170-
if (parentIsRoot) {
171-
return false
172-
} else if (grandParentIsRoot) {
173-
return (
174-
!error.parentIsProperty ||
175-
!ignoreChildrenOf.includes(names[error.parent])
176-
)
177-
} else if (greatGrandparentIsRoot) {
178-
return (
179-
!error.parentIsProperty ||
180-
!ignoreGrandchildrenOf.includes(names[error.grandparent])
181-
)
182-
}
183-
return true
184-
})
174+
/**
175+
* @param {Property | null} prop
176+
* @param {Expression} expr
177+
*/
178+
function isPropertyChain(prop, expr) {
179+
let value = expr
180+
while (value.parent.type === 'TSAsExpression') {
181+
value = value.parent
185182
}
186-
errors.forEach((error) => error.errors.forEach((e) => context.report(e)))
187-
errors = []
183+
return prop === value.parent && prop.value === value
188184
}
189185

190-
const sortTests = {
191-
/** @param {ObjectExpression} node */
186+
return {
192187
ObjectExpression(node) {
193-
if (!stack) {
194-
reportErrors(false)
188+
const isVueObject = utils.getVueObjectType(context, node) != null
189+
let withinVueObject = isVueObject
190+
/** @type {string | null} */
191+
let withinVuePropName = null
192+
let withinVuePropChainLevel = NaN
193+
if (!isVueObject && stack) {
194+
if (stack.withinVueObject && stack.currentProperty) {
195+
const isChain = isPropertyChain(stack.currentProperty, node)
196+
if (isChain) {
197+
if (stack.isVueObject) {
198+
withinVuePropName = utils.getStaticPropertyName(
199+
stack.currentProperty
200+
)
201+
withinVuePropChainLevel = 1
202+
} else {
203+
withinVuePropName = stack.withinVuePropName
204+
withinVuePropChainLevel = stack.withinVuePropChainLevel + 1
205+
}
206+
withinVueObject = true
207+
} else {
208+
withinVueObject = false
209+
}
210+
}
211+
}
212+
213+
let ignore = isVueObject
214+
215+
if (withinVueObject && withinVuePropName != null) {
216+
if (withinVuePropChainLevel === 1) {
217+
if (ignoreChildrenOf.includes(withinVuePropName)) {
218+
ignore = true
219+
}
220+
} else if (withinVuePropChainLevel === 2) {
221+
if (ignoreGrandchildrenOf.includes(withinVuePropName)) {
222+
ignore = true
223+
}
224+
}
195225
}
196226
stack = {
197227
upper: stack,
198-
prevChar: null,
199228
prevName: null,
200229
numKeys: node.properties.length,
201-
parentIsProperty: node.parent.type === 'Property',
202-
errors: []
230+
currentProperty: null,
231+
isVueObject,
232+
withinVueObject,
233+
withinVuePropName,
234+
withinVuePropChainLevel,
235+
ignore
203236
}
204237
},
205-
/** @param {ObjectExpression} node */
206-
'ObjectExpression:exit'(node) {
207-
errors.push({
208-
errors: stack.errors,
209-
hasUpper: !!stack.upper,
210-
parentIsProperty: node.parent.type === 'Property',
211-
parent: stack.upper && stack.upper.prevChar,
212-
grandparent:
213-
stack.upper && stack.upper.upper && stack.upper.upper.prevChar,
214-
greatGrandparent:
215-
stack.upper &&
216-
stack.upper.upper &&
217-
stack.upper.upper.upper &&
218-
stack.upper.upper.upper.prevChar
219-
})
238+
'ObjectExpression:exit'() {
220239
stack = stack.upper
221240
},
222-
/** @param {SpreadElement} node */
223241
SpreadElement(node) {
224242
if (node.parent.type === 'ObjectExpression') {
225243
stack.prevName = null
226-
stack.prevChar = null
227244
}
228245
},
229-
'Program:exit'() {
230-
reportErrors(false)
231-
},
232-
/** @param {Property} node */
233-
Property(node) {
234-
if (node.parent.type === 'ObjectPattern') {
246+
'ObjectExpression > Property'(node) {
247+
stack.currentProperty = node
248+
249+
if (stack.ignore) {
235250
return
236251
}
237-
238252
const prevName = stack.prevName
239253
const numKeys = stack.numKeys
240254
const thisName = getPropertyName(node)
241255

242256
if (thisName !== null) {
243257
stack.prevName = thisName
244-
stack.prevChar = node.range[0]
245-
if (Object.prototype.hasOwnProperty.call(names, node.range[0])) {
246-
throw new Error('Name clash')
247-
}
248-
names[node.range[0]] = thisName
249258
}
250259

251260
if (prevName === null || thisName === null || numKeys < minKeys) {
252261
return
253262
}
254263

255264
if (!isValidOrder(prevName, thisName)) {
256-
stack.errors.push({
265+
context.report({
257266
node,
258267
loc: node.key.loc,
259-
message:
260-
"Expected object keys to be in {{natural}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'.",
268+
messageId: 'sortKeys',
261269
data: {
262270
thisName,
263271
prevName,
@@ -269,11 +277,5 @@ module.exports = {
269277
}
270278
}
271279
}
272-
273-
const execOnVue = utils.executeOnVue(context, () => {
274-
reportErrors(true)
275-
})
276-
277-
return utils.compositingVisitors(sortTests, execOnVue)
278280
}
279281
}

typings/eslint-plugin-vue/util-types/ast/es-ast.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ export interface Property extends HasParentNode {
298298
computed: boolean
299299
key: Expression
300300
value: Expression
301+
parent: ObjectExpression
301302
}
302303
export interface FunctionExpression extends HasParentNode {
303304
type: 'FunctionExpression'
@@ -483,6 +484,7 @@ export interface AssignmentProperty extends HasParentNode {
483484
computed: boolean
484485
key: Expression
485486
value: Pattern
487+
parent: ObjectPattern
486488
}
487489
export interface ArrayPattern extends HasParentNode {
488490
type: 'ArrayPattern'

0 commit comments

Comments
 (0)