eslint-plugin-perfectionist 4.2.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alphabet.d.ts +176 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/dist/rules/sort-array-includes-utils.js +30 -0
- package/dist/rules/sort-array-includes.js +150 -54
- package/dist/rules/sort-array-includes.types.js +10 -0
- package/dist/rules/sort-classes.js +19 -16
- package/dist/rules/sort-decorators.js +11 -6
- package/dist/rules/sort-enums.js +39 -31
- package/dist/rules/sort-exports.js +11 -5
- package/dist/rules/sort-heritage-clauses.js +12 -6
- package/dist/rules/sort-imports.js +34 -21
- package/dist/rules/sort-interfaces.js +3 -1
- package/dist/rules/sort-intersection-types.js +24 -19
- package/dist/rules/sort-jsx-props.js +12 -7
- package/dist/rules/sort-maps.js +18 -13
- package/dist/rules/sort-modules.js +23 -18
- package/dist/rules/sort-named-exports.js +18 -13
- package/dist/rules/sort-named-imports.js +18 -13
- package/dist/rules/sort-object-types.js +149 -103
- package/dist/rules/sort-objects.js +142 -58
- package/dist/rules/sort-sets.js +14 -5
- package/dist/rules/sort-switch-case.js +16 -14
- package/dist/rules/sort-union-types.js +24 -19
- package/dist/rules/sort-variable-declarations.js +18 -13
- package/dist/utils/alphabet.js +385 -0
- package/dist/utils/common-json-schemas.js +27 -5
- package/dist/utils/compare.js +88 -38
- package/dist/utils/convert-boolean-to-sign.js +4 -0
- package/dist/utils/create-node-index-map.js +10 -0
- package/dist/{rules → utils}/get-custom-groups-compare-options.js +1 -0
- package/dist/utils/{get-node-parent.js → get-first-node-parent-with-type.js} +3 -4
- package/dist/utils/get-matching-context-options.js +18 -0
- package/dist/utils/get-settings.js +1 -0
- package/dist/utils/is-node-function-type.js +15 -0
- package/dist/utils/is-partition-comment.js +4 -1
- package/dist/utils/pairwise.js +1 -3
- package/dist/utils/validate-custom-sort-configuration.js +11 -0
- package/dist/{rules → utils}/validate-generated-groups-configuration.js +1 -1
- package/dist/utils/validate-groups-configuration.js +11 -5
- package/package.json +7 -3
- package/readme.md +4 -3
package/dist/rules/sort-sets.js
CHANGED
|
@@ -20,20 +20,29 @@ const sortSets = createEslintRule.createEslintRule({
|
|
|
20
20
|
node.arguments[0].type === 'ArrayExpression'
|
|
21
21
|
? node.arguments[0].elements
|
|
22
22
|
: node.arguments[0].arguments
|
|
23
|
-
sortArrayIncludes.sortArray(
|
|
23
|
+
sortArrayIncludes.sortArray({
|
|
24
|
+
availableMessageIds: {
|
|
25
|
+
unexpectedGroupOrder: 'unexpectedSetsGroupOrder',
|
|
26
|
+
unexpectedOrder: 'unexpectedSetsOrder',
|
|
27
|
+
},
|
|
28
|
+
elements,
|
|
29
|
+
context,
|
|
30
|
+
})
|
|
24
31
|
}
|
|
25
32
|
},
|
|
26
33
|
}),
|
|
27
34
|
meta: {
|
|
35
|
+
messages: {
|
|
36
|
+
unexpectedSetsGroupOrder:
|
|
37
|
+
'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).',
|
|
38
|
+
unexpectedSetsOrder: 'Expected "{{right}}" to come before "{{left}}".',
|
|
39
|
+
},
|
|
28
40
|
docs: {
|
|
29
41
|
url: 'https://perfectionist.dev/rules/sort-sets',
|
|
30
42
|
description: 'Enforce sorted sets.',
|
|
31
43
|
recommended: true,
|
|
32
44
|
},
|
|
33
|
-
|
|
34
|
-
unexpectedSetsOrder: 'Expected "{{right}}" to come before "{{left}}".',
|
|
35
|
-
},
|
|
36
|
-
schema: [sortArrayIncludes.jsonSchema],
|
|
45
|
+
schema: sortArrayIncludes.jsonSchema,
|
|
37
46
|
type: 'suggestion',
|
|
38
47
|
fixable: 'code',
|
|
39
48
|
},
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const commonJsonSchemas = require('../utils/common-json-schemas.js')
|
|
3
|
+
const validateCustomSortConfiguration = require('../utils/validate-custom-sort-configuration.js')
|
|
3
4
|
const makeCommentAfterFixes = require('../utils/make-comment-after-fixes.js')
|
|
5
|
+
const createNodeIndexMap = require('../utils/create-node-index-map.js')
|
|
4
6
|
const createEslintRule = require('../utils/create-eslint-rule.js')
|
|
5
7
|
const getSourceCode = require('../utils/get-source-code.js')
|
|
6
8
|
const rangeToDiff = require('../utils/range-to-diff.js')
|
|
@@ -16,6 +18,7 @@ let defaultOptions = {
|
|
|
16
18
|
type: 'alphabetical',
|
|
17
19
|
ignoreCase: true,
|
|
18
20
|
locales: 'en-US',
|
|
21
|
+
alphabet: '',
|
|
19
22
|
order: 'asc',
|
|
20
23
|
}
|
|
21
24
|
const sortSwitchCase = createEslintRule.createEslintRule({
|
|
@@ -30,6 +33,7 @@ const sortSwitchCase = createEslintRule.createEslintRule({
|
|
|
30
33
|
settings,
|
|
31
34
|
defaultOptions,
|
|
32
35
|
)
|
|
36
|
+
validateCustomSortConfiguration.validateCustomSortConfiguration(options)
|
|
33
37
|
let sourceCode = getSourceCode.getSourceCode(context)
|
|
34
38
|
let isDiscriminantTrue =
|
|
35
39
|
switchNode.discriminant.type === 'Literal' &&
|
|
@@ -67,10 +71,13 @@ const sortSwitchCase = createEslintRule.createEslintRule({
|
|
|
67
71
|
(hasUnsortedNodes = sortedCaseNameSortingNodes.some(
|
|
68
72
|
(node, index) => node !== caseNodesSortingNodeGroup[index],
|
|
69
73
|
))
|
|
74
|
+
let nodeIndexMap = createNodeIndexMap.createNodeIndexMap(
|
|
75
|
+
sortedCaseNameSortingNodes,
|
|
76
|
+
)
|
|
70
77
|
pairwise.pairwise(caseNodesSortingNodeGroup, (left, right) => {
|
|
71
|
-
let
|
|
72
|
-
let
|
|
73
|
-
if (
|
|
78
|
+
let leftIndex = nodeIndexMap.get(left)
|
|
79
|
+
let rightIndex = nodeIndexMap.get(right)
|
|
80
|
+
if (leftIndex < rightIndex) {
|
|
74
81
|
return
|
|
75
82
|
}
|
|
76
83
|
context.report({
|
|
@@ -218,9 +225,10 @@ const sortSwitchCase = createEslintRule.createEslintRule({
|
|
|
218
225
|
properties: {
|
|
219
226
|
specialCharacters: commonJsonSchemas.specialCharactersJsonSchema,
|
|
220
227
|
ignoreCase: commonJsonSchemas.ignoreCaseJsonSchema,
|
|
228
|
+
alphabet: commonJsonSchemas.alphabetJsonSchema,
|
|
229
|
+
type: commonJsonSchemas.buildTypeJsonSchema(),
|
|
221
230
|
locales: commonJsonSchemas.localesJsonSchema,
|
|
222
231
|
order: commonJsonSchemas.orderJsonSchema,
|
|
223
|
-
type: commonJsonSchemas.typeJsonSchema,
|
|
224
232
|
},
|
|
225
233
|
additionalProperties: false,
|
|
226
234
|
type: 'object',
|
|
@@ -263,18 +271,12 @@ let reduceCaseSortingNodes = (caseNodes, endsBlock) =>
|
|
|
263
271
|
)
|
|
264
272
|
let caseHasBreakOrReturn = caseNode => {
|
|
265
273
|
var _a
|
|
266
|
-
|
|
267
|
-
return false
|
|
268
|
-
}
|
|
269
|
-
if (
|
|
274
|
+
let statements =
|
|
270
275
|
((_a = caseNode.consequent[0]) == null ? void 0 : _a.type) ===
|
|
271
276
|
'BlockStatement'
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return caseNode.consequent.some(currentConsequent =>
|
|
276
|
-
statementIsBreakOrReturn(currentConsequent),
|
|
277
|
-
)
|
|
277
|
+
? caseNode.consequent[0].body
|
|
278
|
+
: caseNode.consequent
|
|
279
|
+
return statements.some(statementIsBreakOrReturn)
|
|
278
280
|
}
|
|
279
281
|
let statementIsBreakOrReturn = statement =>
|
|
280
282
|
statement.type === 'BreakStatement' || statement.type === 'ReturnStatement'
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const commonJsonSchemas = require('../utils/common-json-schemas.js')
|
|
3
3
|
const validateNewlinesAndPartitionConfiguration = require('../utils/validate-newlines-and-partition-configuration.js')
|
|
4
|
+
const validateCustomSortConfiguration = require('../utils/validate-custom-sort-configuration.js')
|
|
4
5
|
const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
|
|
5
6
|
const getEslintDisabledLines = require('../utils/get-eslint-disabled-lines.js')
|
|
6
7
|
const isNodeEslintDisabled = require('../utils/is-node-eslint-disabled.js')
|
|
8
|
+
const createNodeIndexMap = require('../utils/create-node-index-map.js')
|
|
7
9
|
const isPartitionComment = require('../utils/is-partition-comment.js')
|
|
8
10
|
const sortNodesByGroups = require('../utils/sort-nodes-by-groups.js')
|
|
9
11
|
const getCommentsBefore = require('../utils/get-comments-before.js')
|
|
@@ -28,6 +30,7 @@ let defaultOptions = {
|
|
|
28
30
|
type: 'alphabetical',
|
|
29
31
|
ignoreCase: true,
|
|
30
32
|
locales: 'en-US',
|
|
33
|
+
alphabet: '',
|
|
31
34
|
order: 'asc',
|
|
32
35
|
groups: [],
|
|
33
36
|
}
|
|
@@ -40,6 +43,7 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
40
43
|
settings,
|
|
41
44
|
defaultOptions,
|
|
42
45
|
)
|
|
46
|
+
validateCustomSortConfiguration.validateCustomSortConfiguration(options)
|
|
43
47
|
validateGroupsConfiguration.validateGroupsConfiguration(
|
|
44
48
|
options.groups,
|
|
45
49
|
[
|
|
@@ -69,7 +73,6 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
69
73
|
})
|
|
70
74
|
let formattedMembers = node.types.reduce(
|
|
71
75
|
(accumulator, type) => {
|
|
72
|
-
var _a, _b
|
|
73
76
|
let { defineGroup, getGroup } = useGroups.useGroups(options)
|
|
74
77
|
switch (type.type) {
|
|
75
78
|
case 'TSTemplateLiteralType':
|
|
@@ -128,8 +131,8 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
128
131
|
defineGroup('union')
|
|
129
132
|
break
|
|
130
133
|
}
|
|
131
|
-
let
|
|
132
|
-
|
|
134
|
+
let lastGroup = accumulator.at(-1)
|
|
135
|
+
let lastSortingNode = lastGroup == null ? void 0 : lastGroup.at(-1)
|
|
133
136
|
let sortingNode = {
|
|
134
137
|
isEslintDisabled: isNodeEslintDisabled.isNodeEslintDisabled(
|
|
135
138
|
type,
|
|
@@ -141,15 +144,14 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
141
144
|
node: type,
|
|
142
145
|
}
|
|
143
146
|
if (
|
|
144
|
-
(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
)) ||
|
|
147
|
+
isPartitionComment.hasPartitionComment(
|
|
148
|
+
options.partitionByComment,
|
|
149
|
+
getCommentsBefore.getCommentsBefore({
|
|
150
|
+
tokenValueToIgnoreBefore: '|',
|
|
151
|
+
node: type,
|
|
152
|
+
sourceCode,
|
|
153
|
+
}),
|
|
154
|
+
) ||
|
|
153
155
|
(options.partitionByNewLine &&
|
|
154
156
|
lastSortingNode &&
|
|
155
157
|
getLinesBetween.getLinesBetween(
|
|
@@ -158,9 +160,10 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
158
160
|
sortingNode,
|
|
159
161
|
))
|
|
160
162
|
) {
|
|
161
|
-
|
|
163
|
+
lastGroup = []
|
|
164
|
+
accumulator.push(lastGroup)
|
|
162
165
|
}
|
|
163
|
-
|
|
166
|
+
lastGroup == null ? void 0 : lastGroup.push(sortingNode)
|
|
164
167
|
return accumulator
|
|
165
168
|
},
|
|
166
169
|
[[]],
|
|
@@ -173,17 +176,18 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
173
176
|
let sortedNodes = sortNodesExcludingEslintDisabled(false)
|
|
174
177
|
let sortedNodesExcludingEslintDisabled =
|
|
175
178
|
sortNodesExcludingEslintDisabled(true)
|
|
179
|
+
let nodeIndexMap = createNodeIndexMap.createNodeIndexMap(sortedNodes)
|
|
176
180
|
pairwise.pairwise(nodes, (left, right) => {
|
|
177
181
|
let leftNumber = getGroupNumber.getGroupNumber(options.groups, left)
|
|
178
182
|
let rightNumber = getGroupNumber.getGroupNumber(options.groups, right)
|
|
179
|
-
let
|
|
180
|
-
let
|
|
183
|
+
let leftIndex = nodeIndexMap.get(left)
|
|
184
|
+
let rightIndex = nodeIndexMap.get(right)
|
|
181
185
|
let indexOfRightExcludingEslintDisabled =
|
|
182
186
|
sortedNodesExcludingEslintDisabled.indexOf(right)
|
|
183
187
|
let messageIds = []
|
|
184
188
|
if (
|
|
185
|
-
|
|
186
|
-
|
|
189
|
+
leftIndex > rightIndex ||
|
|
190
|
+
leftIndex >= indexOfRightExcludingEslintDisabled
|
|
187
191
|
) {
|
|
188
192
|
messageIds.push(
|
|
189
193
|
leftNumber === rightNumber
|
|
@@ -249,10 +253,11 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
249
253
|
specialCharacters: commonJsonSchemas.specialCharactersJsonSchema,
|
|
250
254
|
newlinesBetween: commonJsonSchemas.newlinesBetweenJsonSchema,
|
|
251
255
|
ignoreCase: commonJsonSchemas.ignoreCaseJsonSchema,
|
|
256
|
+
alphabet: commonJsonSchemas.alphabetJsonSchema,
|
|
257
|
+
type: commonJsonSchemas.buildTypeJsonSchema(),
|
|
252
258
|
locales: commonJsonSchemas.localesJsonSchema,
|
|
253
259
|
groups: commonJsonSchemas.groupsJsonSchema,
|
|
254
260
|
order: commonJsonSchemas.orderJsonSchema,
|
|
255
|
-
type: commonJsonSchemas.typeJsonSchema,
|
|
256
261
|
},
|
|
257
262
|
additionalProperties: false,
|
|
258
263
|
type: 'object',
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const commonJsonSchemas = require('../utils/common-json-schemas.js')
|
|
3
3
|
const sortNodesByDependencies = require('../utils/sort-nodes-by-dependencies.js')
|
|
4
|
+
const validateCustomSortConfiguration = require('../utils/validate-custom-sort-configuration.js')
|
|
4
5
|
const getEslintDisabledLines = require('../utils/get-eslint-disabled-lines.js')
|
|
5
6
|
const isNodeEslintDisabled = require('../utils/is-node-eslint-disabled.js')
|
|
7
|
+
const createNodeIndexMap = require('../utils/create-node-index-map.js')
|
|
6
8
|
const isPartitionComment = require('../utils/is-partition-comment.js')
|
|
7
9
|
const getCommentsBefore = require('../utils/get-comments-before.js')
|
|
8
10
|
const createEslintRule = require('../utils/create-eslint-rule.js')
|
|
@@ -23,6 +25,7 @@ let defaultOptions = {
|
|
|
23
25
|
type: 'alphabetical',
|
|
24
26
|
ignoreCase: true,
|
|
25
27
|
locales: 'en-US',
|
|
28
|
+
alphabet: '',
|
|
26
29
|
order: 'asc',
|
|
27
30
|
}
|
|
28
31
|
const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
@@ -37,6 +40,7 @@ const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
|
37
40
|
settings,
|
|
38
41
|
defaultOptions,
|
|
39
42
|
)
|
|
43
|
+
validateCustomSortConfiguration.validateCustomSortConfiguration(options)
|
|
40
44
|
let sourceCode = getSourceCode.getSourceCode(context)
|
|
41
45
|
let eslintDisabledLines = getEslintDisabledLines.getEslintDisabledLines({
|
|
42
46
|
ruleName: context.id,
|
|
@@ -143,14 +147,13 @@ const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
|
143
147
|
name,
|
|
144
148
|
}
|
|
145
149
|
if (
|
|
146
|
-
(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
)) ||
|
|
150
|
+
isPartitionComment.hasPartitionComment(
|
|
151
|
+
options.partitionByComment,
|
|
152
|
+
getCommentsBefore.getCommentsBefore({
|
|
153
|
+
node: declaration,
|
|
154
|
+
sourceCode,
|
|
155
|
+
}),
|
|
156
|
+
) ||
|
|
154
157
|
(options.partitionByNewLine &&
|
|
155
158
|
lastSortingNode &&
|
|
156
159
|
getLinesBetween.getLinesBetween(
|
|
@@ -181,14 +184,15 @@ const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
|
181
184
|
let sortedNodesExcludingEslintDisabled =
|
|
182
185
|
sortNodesIgnoringEslintDisabledNodes(true)
|
|
183
186
|
let nodes = formattedMembers.flat()
|
|
187
|
+
let nodeIndexMap = createNodeIndexMap.createNodeIndexMap(sortedNodes)
|
|
184
188
|
pairwise.pairwise(nodes, (left, right) => {
|
|
185
|
-
let
|
|
186
|
-
let
|
|
189
|
+
let leftIndex = nodeIndexMap.get(left)
|
|
190
|
+
let rightIndex = nodeIndexMap.get(right)
|
|
187
191
|
let indexOfRightExcludingEslintDisabled =
|
|
188
192
|
sortedNodesExcludingEslintDisabled.indexOf(right)
|
|
189
193
|
if (
|
|
190
|
-
|
|
191
|
-
|
|
194
|
+
leftIndex < rightIndex &&
|
|
195
|
+
leftIndex < indexOfRightExcludingEslintDisabled
|
|
192
196
|
) {
|
|
193
197
|
return
|
|
194
198
|
}
|
|
@@ -231,9 +235,10 @@ const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
|
231
235
|
partitionByNewLine: commonJsonSchemas.partitionByNewLineJsonSchema,
|
|
232
236
|
specialCharacters: commonJsonSchemas.specialCharactersJsonSchema,
|
|
233
237
|
ignoreCase: commonJsonSchemas.ignoreCaseJsonSchema,
|
|
238
|
+
alphabet: commonJsonSchemas.alphabetJsonSchema,
|
|
239
|
+
type: commonJsonSchemas.buildTypeJsonSchema(),
|
|
234
240
|
locales: commonJsonSchemas.localesJsonSchema,
|
|
235
241
|
order: commonJsonSchemas.orderJsonSchema,
|
|
236
|
-
type: commonJsonSchemas.typeJsonSchema,
|
|
237
242
|
},
|
|
238
243
|
additionalProperties: false,
|
|
239
244
|
type: 'object',
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
var __defProp = Object.defineProperty
|
|
3
|
+
var __defNormalProp = (obj, key, value) =>
|
|
4
|
+
key in obj
|
|
5
|
+
? __defProp(obj, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value,
|
|
10
|
+
})
|
|
11
|
+
: (obj[key] = value)
|
|
12
|
+
var __publicField = (obj, key, value) =>
|
|
13
|
+
__defNormalProp(obj, typeof key !== 'symbol' ? key + '' : key, value)
|
|
14
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
|
|
15
|
+
const naturalOrderby = require('natural-orderby')
|
|
16
|
+
const convertBooleanToSign = require('./convert-boolean-to-sign.js')
|
|
17
|
+
class Alphabet {
|
|
18
|
+
constructor(characters) {
|
|
19
|
+
__publicField(this, '_characters', [])
|
|
20
|
+
this._characters = characters
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generates an alphabet from the given characters.
|
|
24
|
+
* @param {string|string[]} values - The characters to generate the alphabet from
|
|
25
|
+
* @returns {Alphabet} - The wrapped alphabet
|
|
26
|
+
*/
|
|
27
|
+
static generateFrom(values) {
|
|
28
|
+
let arrayValues = typeof values === 'string' ? [...values] : values
|
|
29
|
+
if (arrayValues.length !== new Set(arrayValues).size) {
|
|
30
|
+
throw new Error('The alphabet must not contain repeated characters')
|
|
31
|
+
}
|
|
32
|
+
if (arrayValues.some(value => value.length !== 1)) {
|
|
33
|
+
throw new Error('The alphabet must contain single characters')
|
|
34
|
+
}
|
|
35
|
+
return new Alphabet(
|
|
36
|
+
arrayValues.map(value =>
|
|
37
|
+
Alphabet._convertCodepointToCharacter(value.codePointAt(0)),
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generates an alphabet containing relevant characters from the Unicode
|
|
43
|
+
* standard. Contains the Unicode planes 0 and 1.
|
|
44
|
+
* @returns {Alphabet} - The generated alphabet
|
|
45
|
+
*/
|
|
46
|
+
static generateRecommendedAlphabet() {
|
|
47
|
+
return Alphabet._generateAlphabetToRange(131071 + 1)
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generates an alphabet containing all characters from the Unicode standard
|
|
51
|
+
* except for irrelevant Unicode planes.
|
|
52
|
+
* Contains the Unicode planes 0, 1, 2 and 3.
|
|
53
|
+
* @returns {Alphabet} - The generated alphabet
|
|
54
|
+
*/
|
|
55
|
+
static generateCompleteAlphabet() {
|
|
56
|
+
return Alphabet._generateAlphabetToRange(262143 + 1)
|
|
57
|
+
}
|
|
58
|
+
static _convertCodepointToCharacter(codePoint) {
|
|
59
|
+
let character = String.fromCodePoint(codePoint)
|
|
60
|
+
let lowercaseCharacter = character.toLowerCase()
|
|
61
|
+
let uppercaseCharacter = character.toUpperCase()
|
|
62
|
+
return {
|
|
63
|
+
value: character,
|
|
64
|
+
codePoint,
|
|
65
|
+
...(lowercaseCharacter === character
|
|
66
|
+
? null
|
|
67
|
+
: {
|
|
68
|
+
lowercaseCharacterCodePoint: lowercaseCharacter.codePointAt(0),
|
|
69
|
+
}),
|
|
70
|
+
...(uppercaseCharacter === character
|
|
71
|
+
? null
|
|
72
|
+
: {
|
|
73
|
+
uppercaseCharacterCodePoint: uppercaseCharacter.codePointAt(0),
|
|
74
|
+
}),
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Generates an alphabet containing relevant characters from the Unicode
|
|
79
|
+
* standard.
|
|
80
|
+
* @param {number} maxCodePoint - The maximum code point to generate the
|
|
81
|
+
* alphabet to
|
|
82
|
+
* @returns {Alphabet} - The generated alphabet
|
|
83
|
+
*/
|
|
84
|
+
static _generateAlphabetToRange(maxCodePoint) {
|
|
85
|
+
let totalCharacters = Array.from({ length: maxCodePoint }, (_, i) =>
|
|
86
|
+
Alphabet._convertCodepointToCharacter(i),
|
|
87
|
+
)
|
|
88
|
+
return new Alphabet(totalCharacters)
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* For each character with a lower and upper case, permutes the two cases
|
|
92
|
+
* so that the alphabet is ordered by the case priority entered.
|
|
93
|
+
* @param {string} casePriority - The case to prioritize
|
|
94
|
+
* @returns {Alphabet} - The same alphabet instance with the cases prioritized
|
|
95
|
+
* @example
|
|
96
|
+
* Alphabet.generateFrom('aAbBcdCD')
|
|
97
|
+
* .prioritizeCase('uppercase')
|
|
98
|
+
* // Returns 'AaBbCDcd'
|
|
99
|
+
*/
|
|
100
|
+
prioritizeCase(casePriority) {
|
|
101
|
+
let charactersWithCase = this._getCharactersWithCase()
|
|
102
|
+
let parsedIndexes = /* @__PURE__ */ new Set()
|
|
103
|
+
let indexByCodePoints = this._characters.reduce(
|
|
104
|
+
(indexByCodePoint, character, index) => {
|
|
105
|
+
indexByCodePoint[character.codePoint] = index
|
|
106
|
+
return indexByCodePoint
|
|
107
|
+
},
|
|
108
|
+
{},
|
|
109
|
+
)
|
|
110
|
+
for (let { character, index } of charactersWithCase) {
|
|
111
|
+
if (parsedIndexes.has(index)) {
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
parsedIndexes.add(index)
|
|
115
|
+
let otherCharacterIndex =
|
|
116
|
+
indexByCodePoints[
|
|
117
|
+
character.uppercaseCharacterCodePoint ??
|
|
118
|
+
character.lowercaseCharacterCodePoint
|
|
119
|
+
]
|
|
120
|
+
if (otherCharacterIndex === void 0) {
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
parsedIndexes.add(otherCharacterIndex)
|
|
124
|
+
let isCharacterUppercase = !character.uppercaseCharacterCodePoint
|
|
125
|
+
if (isCharacterUppercase) {
|
|
126
|
+
if (
|
|
127
|
+
(casePriority === 'uppercase' && index < otherCharacterIndex) ||
|
|
128
|
+
(casePriority === 'lowercase' && index > otherCharacterIndex)
|
|
129
|
+
) {
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
if (
|
|
134
|
+
(casePriority === 'uppercase' && index > otherCharacterIndex) ||
|
|
135
|
+
(casePriority === 'lowercase' && index < otherCharacterIndex)
|
|
136
|
+
) {
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
this._characters[index] = this._characters[otherCharacterIndex]
|
|
141
|
+
this._characters[otherCharacterIndex] = character
|
|
142
|
+
}
|
|
143
|
+
return this
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Adds specific characters to the end of the alphabet.
|
|
147
|
+
* @param {string|string[]} values - The characters to push to the alphabet
|
|
148
|
+
* @returns {Alphabet} - The same alphabet instance without the specified
|
|
149
|
+
* characters
|
|
150
|
+
* @example
|
|
151
|
+
* Alphabet.generateFrom('ab')
|
|
152
|
+
* .pushCharacters('cd')
|
|
153
|
+
* // Returns 'abcd'
|
|
154
|
+
*/
|
|
155
|
+
pushCharacters(values) {
|
|
156
|
+
let arrayValues = typeof values === 'string' ? [...values] : values
|
|
157
|
+
let valuesSet = new Set(arrayValues)
|
|
158
|
+
let valuesAlreadyExisting = this._characters.filter(({ value }) =>
|
|
159
|
+
valuesSet.has(value),
|
|
160
|
+
)
|
|
161
|
+
if (valuesAlreadyExisting.length > 0) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`The alphabet already contains the characters ${valuesAlreadyExisting
|
|
164
|
+
.slice(0, 5)
|
|
165
|
+
.map(({ value }) => value)
|
|
166
|
+
.join(', ')}`,
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
if (arrayValues.some(value => value.length !== 1)) {
|
|
170
|
+
throw new Error('Only single characters may be pushed')
|
|
171
|
+
}
|
|
172
|
+
this._characters.push(
|
|
173
|
+
...[...valuesSet].map(value =>
|
|
174
|
+
Alphabet._convertCodepointToCharacter(value.codePointAt(0)),
|
|
175
|
+
),
|
|
176
|
+
)
|
|
177
|
+
return this
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Permutes characters with cases so that all characters with the entered case
|
|
181
|
+
* are put before the other characters.
|
|
182
|
+
* @param {string} caseToComeFirst - The case to put before the other
|
|
183
|
+
* characters
|
|
184
|
+
* @returns {Alphabet} - The same alphabet instance with all characters with
|
|
185
|
+
* case before all the characters with the other case
|
|
186
|
+
*/
|
|
187
|
+
placeAllWithCaseBeforeAllWithOtherCase(caseToComeFirst) {
|
|
188
|
+
let charactersWithCase = this._getCharactersWithCase()
|
|
189
|
+
let orderedCharacters = [
|
|
190
|
+
...charactersWithCase.filter(character =>
|
|
191
|
+
caseToComeFirst === 'uppercase'
|
|
192
|
+
? !character.character.uppercaseCharacterCodePoint
|
|
193
|
+
: character.character.uppercaseCharacterCodePoint,
|
|
194
|
+
),
|
|
195
|
+
...charactersWithCase.filter(character =>
|
|
196
|
+
caseToComeFirst === 'uppercase'
|
|
197
|
+
? character.character.uppercaseCharacterCodePoint
|
|
198
|
+
: !character.character.uppercaseCharacterCodePoint,
|
|
199
|
+
),
|
|
200
|
+
]
|
|
201
|
+
for (let [i, element] of charactersWithCase.entries()) {
|
|
202
|
+
this._characters[element.index] = orderedCharacters[i].character
|
|
203
|
+
}
|
|
204
|
+
return this
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Places a specific character right before another character in the alphabet.
|
|
208
|
+
* @param {object} params - The parameters for the operation
|
|
209
|
+
* @param {string} params.characterBefore - The character to come before
|
|
210
|
+
* characterAfter
|
|
211
|
+
* @param {string} params.characterAfter - The target character
|
|
212
|
+
* @returns {Alphabet} - The same alphabet instance with the specific
|
|
213
|
+
* character prioritized
|
|
214
|
+
* @example
|
|
215
|
+
* Alphabet.generateFrom('ab-cd/')
|
|
216
|
+
* .placeCharacterBefore({ characterBefore: '/', characterAfter: '-' })
|
|
217
|
+
* // Returns 'ab/-cd'
|
|
218
|
+
*/
|
|
219
|
+
placeCharacterBefore({ characterBefore, characterAfter }) {
|
|
220
|
+
return this._placeCharacterBeforeOrAfter({
|
|
221
|
+
characterBefore,
|
|
222
|
+
characterAfter,
|
|
223
|
+
type: 'before',
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Places a specific character right after another character in the alphabet.
|
|
228
|
+
* @param {object} params - The parameters for the operation
|
|
229
|
+
* @param {string} params.characterBefore - The target character
|
|
230
|
+
* @param {string} params.characterAfter - The character to come after
|
|
231
|
+
* characterBefore
|
|
232
|
+
* @returns {Alphabet} - The same alphabet instance with the specific
|
|
233
|
+
* character prioritized
|
|
234
|
+
* @example
|
|
235
|
+
* Alphabet.generateFrom('ab-cd/')
|
|
236
|
+
* .placeCharacterAfter({ characterBefore: '/', characterAfter: '-' })
|
|
237
|
+
* // Returns 'abcd/-'
|
|
238
|
+
*/
|
|
239
|
+
placeCharacterAfter({ characterBefore, characterAfter }) {
|
|
240
|
+
return this._placeCharacterBeforeOrAfter({
|
|
241
|
+
characterBefore,
|
|
242
|
+
characterAfter,
|
|
243
|
+
type: 'after',
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Removes specific characters from the alphabet by their range.
|
|
248
|
+
* @param {object} range - The Unicode range to remove characters from
|
|
249
|
+
* @param {number} range.start - The starting Unicode codepoint
|
|
250
|
+
* @param {number} range.end - The ending Unicode codepoint
|
|
251
|
+
* @returns {Alphabet} - The same alphabet instance without the characters
|
|
252
|
+
* from the specified range
|
|
253
|
+
*/
|
|
254
|
+
removeUnicodeRange({ start, end }) {
|
|
255
|
+
this._characters = this._characters.filter(
|
|
256
|
+
({ codePoint }) => codePoint < start || codePoint > end,
|
|
257
|
+
)
|
|
258
|
+
return this
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Sorts the alphabet by the sorting function provided.
|
|
262
|
+
* @param {Function} sortingFunction - The sorting function to use
|
|
263
|
+
* @returns {Alphabet} - The same alphabet instance sorted by the sorting function provided
|
|
264
|
+
*/
|
|
265
|
+
sortBy(sortingFunction) {
|
|
266
|
+
this._characters.sort((a, b) => sortingFunction(a.value, b.value))
|
|
267
|
+
return this
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Removes specific characters from the alphabet.
|
|
271
|
+
* @param {string|string[]} values - The characters to remove from the
|
|
272
|
+
* alphabet
|
|
273
|
+
* @returns {Alphabet} - The same alphabet instance without the specified
|
|
274
|
+
* characters
|
|
275
|
+
* @example
|
|
276
|
+
* Alphabet.generateFrom('abcd')
|
|
277
|
+
* .removeCharacters('dcc')
|
|
278
|
+
* // Returns 'ab'
|
|
279
|
+
*/
|
|
280
|
+
removeCharacters(values) {
|
|
281
|
+
this._characters = this._characters.filter(
|
|
282
|
+
({ value }) => !values.includes(value),
|
|
283
|
+
)
|
|
284
|
+
return this
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Sorts the alphabet by the natural order of the characters using
|
|
288
|
+
* `natural-orderby`.
|
|
289
|
+
* @param {string} locale - The locale to use for sorting
|
|
290
|
+
* @returns {Alphabet} - The same alphabet instance sorted by the natural
|
|
291
|
+
* order of the characters
|
|
292
|
+
*/
|
|
293
|
+
sortByNaturalSort(locale) {
|
|
294
|
+
let naturalCompare = naturalOrderby.compare({
|
|
295
|
+
locale,
|
|
296
|
+
})
|
|
297
|
+
return this.sortBy((a, b) => naturalCompare(a, b))
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Sorts the alphabet by the character code point.
|
|
301
|
+
* @returns {Alphabet} - The same alphabet instance sorted by the character
|
|
302
|
+
* code point
|
|
303
|
+
*/
|
|
304
|
+
sortByCharCodeAt() {
|
|
305
|
+
return this.sortBy((a, b) =>
|
|
306
|
+
convertBooleanToSign.convertBooleanToSign(
|
|
307
|
+
a.charCodeAt(0) > b.charCodeAt(0),
|
|
308
|
+
),
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Sorts the alphabet by the locale order of the characters.
|
|
313
|
+
* @param {Intl.LocalesArgument} locales - The locales to use for sorting
|
|
314
|
+
* @returns {Alphabet} - The same alphabet instance sorted by the locale
|
|
315
|
+
* order of the characters
|
|
316
|
+
*/
|
|
317
|
+
sortByLocaleCompare(locales) {
|
|
318
|
+
return this.sortBy((a, b) => a.localeCompare(b, locales))
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Retrieves the characters from the alphabet.
|
|
322
|
+
* @returns {string} The characters from the alphabet
|
|
323
|
+
*/
|
|
324
|
+
getCharacters() {
|
|
325
|
+
return this._characters.map(({ value }) => value).join('')
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Reverses the alphabet.
|
|
329
|
+
* @returns {Alphabet} - The same alphabet instance reversed
|
|
330
|
+
* @example
|
|
331
|
+
* Alphabet.generateFrom('ab')
|
|
332
|
+
* .reverse()
|
|
333
|
+
* // Returns 'ba'
|
|
334
|
+
*/
|
|
335
|
+
reverse() {
|
|
336
|
+
this._characters.reverse()
|
|
337
|
+
return this
|
|
338
|
+
}
|
|
339
|
+
_placeCharacterBeforeOrAfter({ characterBefore, characterAfter, type }) {
|
|
340
|
+
let indexOfCharacterAfter = this._characters.findIndex(
|
|
341
|
+
({ value }) => value === characterAfter,
|
|
342
|
+
)
|
|
343
|
+
let indexOfCharacterBefore = this._characters.findIndex(
|
|
344
|
+
({ value }) => value === characterBefore,
|
|
345
|
+
)
|
|
346
|
+
if (indexOfCharacterAfter === -1) {
|
|
347
|
+
throw new Error(`Character ${characterAfter} not found in alphabet`)
|
|
348
|
+
}
|
|
349
|
+
if (indexOfCharacterBefore === -1) {
|
|
350
|
+
throw new Error(`Character ${characterBefore} not found in alphabet`)
|
|
351
|
+
}
|
|
352
|
+
if (indexOfCharacterBefore <= indexOfCharacterAfter) {
|
|
353
|
+
return this
|
|
354
|
+
}
|
|
355
|
+
this._characters.splice(
|
|
356
|
+
type === 'before' ? indexOfCharacterAfter : indexOfCharacterBefore + 1,
|
|
357
|
+
0,
|
|
358
|
+
this._characters[
|
|
359
|
+
type === 'before' ? indexOfCharacterBefore : indexOfCharacterAfter
|
|
360
|
+
],
|
|
361
|
+
)
|
|
362
|
+
this._characters.splice(
|
|
363
|
+
type === 'before' ? indexOfCharacterBefore + 1 : indexOfCharacterAfter,
|
|
364
|
+
1,
|
|
365
|
+
)
|
|
366
|
+
return this
|
|
367
|
+
}
|
|
368
|
+
_getCharactersWithCase() {
|
|
369
|
+
return this._characters
|
|
370
|
+
.map((character, index) => {
|
|
371
|
+
if (
|
|
372
|
+
!character.uppercaseCharacterCodePoint &&
|
|
373
|
+
!character.lowercaseCharacterCodePoint
|
|
374
|
+
) {
|
|
375
|
+
return null
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
character,
|
|
379
|
+
index,
|
|
380
|
+
}
|
|
381
|
+
})
|
|
382
|
+
.filter(element => element !== null)
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
exports.Alphabet = Alphabet
|