Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Loren
committed
Dec 5, 2019
1 parent
e8f130c
commit 686e59f
Showing
6 changed files
with
1,326 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
--- | ||
pageClass: rule-details | ||
sidebarDepth: 0 | ||
title: vue/sort-keys | ||
description: enforce sort-keys in a manner that is compatible with order-in-components | ||
--- | ||
# vue/sort-keys | ||
> enforce sort-keys within components after the top level details | ||
This rule is almost the same rule as core [sorts-keys] rule but it will not error on top component properties allowing that order to be enforced with `order-in-components`. | ||
|
||
## Options | ||
|
||
```json | ||
{ | ||
"sort-keys": ["error", "asc", {"caseSensitive": true, "natural": false, "minKeys": 2}] | ||
} | ||
``` | ||
|
||
The 1st option is `"asc"` or `"desc"`. | ||
|
||
* `"asc"` (default) - enforce properties to be in ascending order. | ||
* `"desc"` - enforce properties to be in descending order. | ||
|
||
The 2nd option is an object which has 3 properties. | ||
|
||
* `caseSensitive` - if `true`, enforce properties to be in case-sensitive order. Default is `true`. | ||
* `minKeys` - Specifies the minimum number of keys that an object should have in order for the object's unsorted keys to produce an error. Default is `2`, which means by default all objects with unsorted keys will result in lint errors. | ||
* `natural` - if `true`, enforce properties to be in natural order. Default is `false`. Natural Order compares strings containing combination of letters and numbers in the way a human being would sort. It basically sorts numerically, instead of sorting alphabetically. So the number 10 comes after the number 3 in Natural Sorting. | ||
|
||
While using this rule, you may disable the normal `sort-keys` rule. This rule will apply to plain js files as well as Vue component scripts. | ||
|
||
## :books: Further reading | ||
|
||
- [sorts-keys] | ||
|
||
[sorts-keys]: https://eslint.org/docs/rules/sorts-keys | ||
|
||
## :mag: Implementation | ||
|
||
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/sort-keys.js) | ||
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/sort-keys.js) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
/** | ||
* @fileoverview enforce sort-keys in a manner that is compatible with order-in-components | ||
* @author Loren Klingman | ||
* Original ESLint sort-keys by Toru Nagashima | ||
*/ | ||
'use strict' | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Requirements | ||
// ------------------------------------------------------------------------------ | ||
|
||
const naturalCompare = require('natural-compare') | ||
const utils = require('../utils') | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Helpers | ||
// ------------------------------------------------------------------------------ | ||
|
||
/** | ||
* Gets the property name of the given `Property` node. | ||
* | ||
* - If the property's key is an `Identifier` node, this returns the key's name | ||
* whether it's a computed property or not. | ||
* - If the property has a static name, this returns the static name. | ||
* - Otherwise, this returns null. | ||
* @param {ASTNode} node The `Property` node to get. | ||
* @returns {string|null} The property name or null. | ||
* @private | ||
*/ | ||
function getPropertyName (node) { | ||
const staticName = utils.getStaticPropertyName(node) | ||
|
||
if (staticName !== null) { | ||
return staticName | ||
} | ||
|
||
return node.key.name || null | ||
} | ||
|
||
/** | ||
* Functions which check that the given 2 names are in specific order. | ||
* | ||
* Postfix `I` is meant insensitive. | ||
* Postfix `N` is meant natual. | ||
* @private | ||
*/ | ||
const isValidOrders = { | ||
asc (a, b) { | ||
return a <= b | ||
}, | ||
ascI (a, b) { | ||
return a.toLowerCase() <= b.toLowerCase() | ||
}, | ||
ascN (a, b) { | ||
return naturalCompare(a, b) <= 0 | ||
}, | ||
ascIN (a, b) { | ||
return naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0 | ||
}, | ||
desc (a, b) { | ||
return isValidOrders.asc(b, a) | ||
}, | ||
descI (a, b) { | ||
return isValidOrders.ascI(b, a) | ||
}, | ||
descN (a, b) { | ||
return isValidOrders.ascN(b, a) | ||
}, | ||
descIN (a, b) { | ||
return isValidOrders.ascIN(b, a) | ||
} | ||
} | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Rule Definition | ||
// ------------------------------------------------------------------------------ | ||
|
||
module.exports = { | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: 'enforce sort-keys in a manner that is compatible with order-in-components', | ||
category: null, | ||
recommended: false, | ||
url: 'https://eslint.vuejs.org/rules/sort-keys.html' | ||
}, | ||
fixable: null, | ||
schema: [ | ||
{ | ||
enum: ['asc', 'desc'] | ||
}, | ||
{ | ||
type: 'object', | ||
properties: { | ||
caseSensitive: { | ||
type: 'boolean', | ||
default: true | ||
}, | ||
natural: { | ||
type: 'boolean', | ||
default: false | ||
}, | ||
minKeys: { | ||
type: 'integer', | ||
minimum: 2, | ||
default: 2 | ||
}, | ||
runOutsideVue: { | ||
type: 'boolean', | ||
default: true | ||
} | ||
}, | ||
additionalProperties: false | ||
} | ||
] | ||
}, | ||
|
||
create (context) { | ||
// Parse options. | ||
const order = context.options[0] || 'asc' | ||
const options = context.options[1] | ||
const insensitive = options && options.caseSensitive === false | ||
const natual = options && options.natural | ||
const minKeys = options && options.minKeys | ||
const isValidOrder = isValidOrders[ | ||
order + (insensitive ? 'I' : '') + (natual ? 'N' : '') | ||
] | ||
|
||
// The stack to save the previous property's name for each object literals. | ||
let stack = null | ||
|
||
let errors = [] | ||
|
||
const reportErrors = (isVue) => { | ||
if (isVue) { | ||
errors = errors.filter((error) => error.hasUpper) | ||
} | ||
errors.forEach((error) => context.report(error)) | ||
errors = [] | ||
} | ||
|
||
const sortTests = { | ||
ObjectExpression (node) { | ||
if (!stack) { | ||
reportErrors(false) | ||
} | ||
stack = { | ||
upper: stack, | ||
prevName: null, | ||
numKeys: node.properties.length | ||
} | ||
}, | ||
'ObjectExpression:exit' () { | ||
// stolen by the VueComponent code | ||
stack = stack.upper | ||
}, | ||
SpreadElement (node) { | ||
if (node.parent.type === 'ObjectExpression') { | ||
stack.prevName = null | ||
} | ||
}, | ||
'Program:exit' () { | ||
reportErrors(false) | ||
}, | ||
Property (node) { | ||
if (node.parent.type === 'ObjectPattern') { | ||
return | ||
} | ||
|
||
const prevName = stack.prevName | ||
const numKeys = stack.numKeys | ||
const thisName = getPropertyName(node) | ||
|
||
if (thisName !== null) { | ||
stack.prevName = thisName | ||
} | ||
|
||
if (prevName === null || thisName === null || numKeys < minKeys) { | ||
return | ||
} | ||
|
||
if (!isValidOrder(prevName, thisName)) { | ||
errors.push({ | ||
node, | ||
hasUpper: !!stack.upper, | ||
loc: node.key.loc, | ||
message: "Expected object keys to be in {{natual}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'.", | ||
data: { | ||
thisName, | ||
prevName, | ||
order, | ||
insensitive: insensitive ? 'insensitive ' : '', | ||
natual: natual ? 'natural ' : '' | ||
} | ||
}) | ||
} | ||
} | ||
} | ||
|
||
const execOnVue = utils.executeOnVue(context, (obj) => { | ||
reportErrors(true) | ||
}) | ||
|
||
const result = { ...sortTests } | ||
|
||
Object.keys(execOnVue).forEach((key) => { | ||
if (Object.prototype.hasOwnProperty.call(sortTests, key)) { | ||
result[key] = (node) => { | ||
sortTests[key](node) | ||
execOnVue[key](node) | ||
} | ||
} else { | ||
result[key] = execOnVue[key] | ||
} | ||
}) | ||
|
||
return result | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.