eslint-plugin-perfectionist
Version:
ESLint plugin for sorting various data such as objects, imports, types, enums, JSX props, etc.
163 lines (162 loc) • 4.79 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
const naturalOrderby = require('natural-orderby')
const convertBooleanToSign = require('./convert-boolean-to-sign.js')
let alphabetCache = /* @__PURE__ */ new Map()
let compare = ({
fallbackSortNodeValueGetter,
nodeValueGetter,
options,
a,
b,
}) => {
if (options.type === 'unsorted') {
return 0
}
let finalNodeValueGetter = nodeValueGetter ?? (node => node.name)
let compareValue = computeCompareValue({
nodeValueGetter: finalNodeValueGetter,
options,
a,
b,
})
if (compareValue) {
return compareValue
}
let { fallbackSort, order } = options
return computeCompareValue({
options: {
...options,
order: fallbackSort.order ?? order,
type: fallbackSort.type,
},
nodeValueGetter: fallbackSortNodeValueGetter ?? finalNodeValueGetter,
a,
b,
})
}
let computeCompareValue = ({ nodeValueGetter, options, a, b }) => {
let sortingFunction
switch (options.type) {
case 'alphabetical':
sortingFunction = getAlphabeticalSortingFunction(options, nodeValueGetter)
break
case 'line-length':
sortingFunction = getLineLengthSortingFunction(options, nodeValueGetter)
break
case 'unsorted':
return 0
case 'natural':
sortingFunction = getNaturalSortingFunction(options, nodeValueGetter)
break
case 'custom':
sortingFunction = getCustomSortingFunction(options, nodeValueGetter)
break
}
return (
convertBooleanToSign.convertBooleanToSign(options.order === 'asc') *
sortingFunction(a, b)
)
}
let getAlphabeticalSortingFunction = (
{ specialCharacters, ignoreCase, locales },
nodeValueGetter,
) => {
let formatString = getFormatStringFunction(ignoreCase, specialCharacters)
return (aNode, bNode) =>
formatString(nodeValueGetter(aNode)).localeCompare(
formatString(nodeValueGetter(bNode)),
locales,
)
}
let getNaturalSortingFunction = (
{ specialCharacters, ignoreCase, locales },
nodeValueGetter,
) => {
let naturalCompare = naturalOrderby.compare({
locale: locales.toString(),
})
let formatString = getFormatStringFunction(ignoreCase, specialCharacters)
return (aNode, bNode) =>
naturalCompare(
formatString(nodeValueGetter(aNode)),
formatString(nodeValueGetter(bNode)),
)
}
let getCustomSortingFunction = (
{ specialCharacters, ignoreCase, alphabet },
nodeValueGetter,
) => {
let formatString = getFormatStringFunction(ignoreCase, specialCharacters)
let indexByCharacters = alphabetCache.get(alphabet)
if (!indexByCharacters) {
indexByCharacters = /* @__PURE__ */ new Map()
for (let [index, character] of [...alphabet].entries()) {
indexByCharacters.set(character, index)
}
alphabetCache.set(alphabet, indexByCharacters)
}
return (aNode, bNode) => {
let aValue = formatString(nodeValueGetter(aNode))
let bValue = formatString(nodeValueGetter(bNode))
let minLength = Math.min(aValue.length, bValue.length)
for (let i = 0; i < minLength; i++) {
let aCharacter = aValue[i]
let bCharacter = bValue[i]
let indexOfA = indexByCharacters.get(aCharacter)
let indexOfB = indexByCharacters.get(bCharacter)
indexOfA ?? (indexOfA = Infinity)
indexOfB ?? (indexOfB = Infinity)
if (indexOfA !== indexOfB) {
return convertBooleanToSign.convertBooleanToSign(
indexOfA - indexOfB > 0,
)
}
}
if (aValue.length === bValue.length) {
return 0
}
return convertBooleanToSign.convertBooleanToSign(
aValue.length - bValue.length > 0,
)
}
}
let getLineLengthSortingFunction =
({ maxLineLength }, nodeValueGetter) =>
(aNode, bNode) => {
let aSize = aNode.size
let bSize = bNode.size
if (maxLineLength) {
let isTooLong = (size, node) =>
size > maxLineLength && node.hasMultipleImportDeclarations
if (isTooLong(aSize, aNode)) {
aSize = nodeValueGetter(aNode).length + 10
}
if (isTooLong(bSize, bNode)) {
bSize = nodeValueGetter(bNode).length + 10
}
}
return aSize - bSize
}
let getFormatStringFunction = (ignoreCase, specialCharacters) => value => {
let valueToCompare = value
if (ignoreCase) {
valueToCompare = valueToCompare.toLowerCase()
}
switch (specialCharacters) {
case 'remove':
valueToCompare = valueToCompare.replaceAll(
/[^a-z\u{C0}-\u{24F}\u{1E00}-\u{1EFF}]+/giu,
'',
)
break
case 'trim':
valueToCompare = valueToCompare.replaceAll(
/^[^a-z\u{C0}-\u{24F}\u{1E00}-\u{1EFF}]+/giu,
'',
)
break
}
return valueToCompare.replaceAll(/\s/gu, '')
}
exports.compare = compare