eslint-plugin-perfectionist 4.1.2 → 4.3.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 +9 -1
- package/dist/rules/sort-array-includes.js +6 -1
- package/dist/rules/sort-classes-utils.js +0 -23
- package/dist/rules/sort-classes.js +19 -43
- package/dist/rules/sort-classes.types.js +5 -37
- package/dist/rules/sort-decorators.js +9 -1
- package/dist/rules/sort-enums.js +11 -1
- package/dist/rules/sort-exports.js +8 -1
- package/dist/rules/sort-heritage-clauses.js +4 -0
- package/dist/rules/sort-imports.js +8 -3
- package/dist/rules/sort-interfaces.js +17 -260
- package/dist/rules/sort-intersection-types.js +9 -1
- package/dist/rules/sort-jsx-props.js +4 -0
- package/dist/rules/sort-maps.js +8 -1
- package/dist/rules/sort-modules-utils.js +0 -23
- package/dist/rules/sort-modules.js +20 -44
- package/dist/rules/sort-modules.types.js +5 -41
- package/dist/rules/sort-named-exports.js +8 -1
- package/dist/rules/sort-named-imports.js +8 -1
- package/dist/rules/sort-object-types-utils.js +37 -0
- package/dist/rules/sort-object-types.js +345 -223
- package/dist/rules/sort-object-types.types.js +20 -0
- package/dist/rules/sort-objects.js +36 -10
- package/dist/rules/sort-switch-case.js +4 -0
- package/dist/rules/sort-union-types.js +9 -1
- package/dist/rules/sort-variable-declarations.js +8 -1
- package/dist/utils/alphabet.js +385 -0
- package/dist/utils/common-json-schemas.js +94 -1
- package/dist/utils/compare.js +88 -39
- package/dist/utils/convert-boolean-to-sign.js +4 -0
- package/dist/utils/get-comments-before.js +4 -4
- package/dist/utils/get-custom-groups-compare-options.js +29 -0
- package/dist/utils/get-matching-context-options.js +18 -0
- package/dist/utils/get-node-range.js +18 -7
- package/dist/utils/get-settings.js +1 -0
- package/dist/utils/is-node-function-type.js +15 -0
- package/dist/utils/make-fixes.js +24 -3
- package/dist/utils/make-newlines-fixes.js +7 -4
- package/dist/utils/validate-custom-sort-configuration.js +11 -0
- package/dist/{rules → utils}/validate-generated-groups-configuration.js +4 -2
- package/package.json +9 -5
- package/readme.md +4 -3
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
const commonJsonSchemas = require('../utils/common-json-schemas.js')
|
|
3
3
|
const sortNodesByDependencies = require('../utils/sort-nodes-by-dependencies.js')
|
|
4
4
|
const validateNewlinesAndPartitionConfiguration = require('../utils/validate-newlines-and-partition-configuration.js')
|
|
5
|
+
const validateCustomSortConfiguration = require('../utils/validate-custom-sort-configuration.js')
|
|
5
6
|
const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
|
|
7
|
+
const getMatchingContextOptions = require('../utils/get-matching-context-options.js')
|
|
6
8
|
const getEslintDisabledLines = require('../utils/get-eslint-disabled-lines.js')
|
|
7
9
|
const isNodeEslintDisabled = require('../utils/is-node-eslint-disabled.js')
|
|
8
10
|
const isPartitionComment = require('../utils/is-partition-comment.js')
|
|
@@ -33,11 +35,13 @@ let defaultOptions = {
|
|
|
33
35
|
objectDeclarations: true,
|
|
34
36
|
styledComponents: true,
|
|
35
37
|
destructureOnly: false,
|
|
38
|
+
useConfigurationIf: {},
|
|
36
39
|
type: 'alphabetical',
|
|
37
40
|
ignorePattern: [],
|
|
38
41
|
ignoreCase: true,
|
|
39
42
|
customGroups: {},
|
|
40
43
|
locales: 'en-US',
|
|
44
|
+
alphabet: '',
|
|
41
45
|
order: 'asc',
|
|
42
46
|
groups: [],
|
|
43
47
|
}
|
|
@@ -48,11 +52,20 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
48
52
|
return
|
|
49
53
|
}
|
|
50
54
|
let settings = getSettings.getSettings(context.settings)
|
|
55
|
+
let sourceCode = getSourceCode.getSourceCode(context)
|
|
56
|
+
let matchedContextOptions =
|
|
57
|
+
getMatchingContextOptions.getMatchingContextOptions({
|
|
58
|
+
nodeNames: nodeObject.properties
|
|
59
|
+
.map(property => getNodeName({ sourceCode, property }))
|
|
60
|
+
.filter(nodeName => nodeName !== null),
|
|
61
|
+
contextOptions: context.options,
|
|
62
|
+
})
|
|
51
63
|
let options = complete.complete(
|
|
52
|
-
|
|
64
|
+
matchedContextOptions,
|
|
53
65
|
settings,
|
|
54
66
|
defaultOptions,
|
|
55
67
|
)
|
|
68
|
+
validateCustomSortConfiguration.validateCustomSortConfiguration(options)
|
|
56
69
|
validateGroupsConfiguration.validateGroupsConfiguration(
|
|
57
70
|
options.groups,
|
|
58
71
|
['multiline', 'method', 'unknown'],
|
|
@@ -130,7 +143,6 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
130
143
|
) {
|
|
131
144
|
return
|
|
132
145
|
}
|
|
133
|
-
let sourceCode = getSourceCode.getSourceCode(context)
|
|
134
146
|
let eslintDisabledLines = getEslintDisabledLines.getEslintDisabledLines({
|
|
135
147
|
ruleName: context.id,
|
|
136
148
|
sourceCode,
|
|
@@ -218,10 +230,6 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
218
230
|
accumulator.push([])
|
|
219
231
|
return accumulator
|
|
220
232
|
}
|
|
221
|
-
let comments = getCommentsBefore.getCommentsBefore(
|
|
222
|
-
property,
|
|
223
|
-
sourceCode,
|
|
224
|
-
)
|
|
225
233
|
let lastProperty =
|
|
226
234
|
(_a = accumulator.at(-1)) == null ? void 0 : _a.at(-1)
|
|
227
235
|
let name
|
|
@@ -270,7 +278,10 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
270
278
|
(options.partitionByComment &&
|
|
271
279
|
isPartitionComment.hasPartitionComment(
|
|
272
280
|
options.partitionByComment,
|
|
273
|
-
|
|
281
|
+
getCommentsBefore.getCommentsBefore({
|
|
282
|
+
node: property,
|
|
283
|
+
sourceCode,
|
|
284
|
+
}),
|
|
274
285
|
))
|
|
275
286
|
) {
|
|
276
287
|
accumulator.push([])
|
|
@@ -383,8 +394,8 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
383
394
|
}
|
|
384
395
|
},
|
|
385
396
|
meta: {
|
|
386
|
-
schema:
|
|
387
|
-
{
|
|
397
|
+
schema: {
|
|
398
|
+
items: {
|
|
388
399
|
properties: {
|
|
389
400
|
destructuredObjects: {
|
|
390
401
|
oneOf: [
|
|
@@ -431,10 +442,12 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
431
442
|
type: 'boolean',
|
|
432
443
|
},
|
|
433
444
|
partitionByNewLine: commonJsonSchemas.partitionByNewLineJsonSchema,
|
|
445
|
+
useConfigurationIf: commonJsonSchemas.useConfigurationIfJsonSchema,
|
|
434
446
|
specialCharacters: commonJsonSchemas.specialCharactersJsonSchema,
|
|
435
447
|
newlinesBetween: commonJsonSchemas.newlinesBetweenJsonSchema,
|
|
436
448
|
customGroups: commonJsonSchemas.customGroupsJsonSchema,
|
|
437
449
|
ignoreCase: commonJsonSchemas.ignoreCaseJsonSchema,
|
|
450
|
+
alphabet: commonJsonSchemas.alphabetJsonSchema,
|
|
438
451
|
locales: commonJsonSchemas.localesJsonSchema,
|
|
439
452
|
groups: commonJsonSchemas.groupsJsonSchema,
|
|
440
453
|
order: commonJsonSchemas.orderJsonSchema,
|
|
@@ -443,7 +456,9 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
443
456
|
additionalProperties: false,
|
|
444
457
|
type: 'object',
|
|
445
458
|
},
|
|
446
|
-
|
|
459
|
+
uniqueItems: true,
|
|
460
|
+
type: 'array',
|
|
461
|
+
},
|
|
447
462
|
messages: {
|
|
448
463
|
unexpectedObjectsGroupOrder:
|
|
449
464
|
'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).',
|
|
@@ -466,4 +481,15 @@ const sortObjects = createEslintRule.createEslintRule({
|
|
|
466
481
|
defaultOptions: [defaultOptions],
|
|
467
482
|
name: 'sort-objects',
|
|
468
483
|
})
|
|
484
|
+
let getNodeName = ({ sourceCode, property }) => {
|
|
485
|
+
if (property.type === 'SpreadElement' || property.type === 'RestElement') {
|
|
486
|
+
return null
|
|
487
|
+
}
|
|
488
|
+
if (property.key.type === 'Identifier') {
|
|
489
|
+
return property.key.name
|
|
490
|
+
} else if (property.key.type === 'Literal') {
|
|
491
|
+
return `${property.key.value}`
|
|
492
|
+
}
|
|
493
|
+
return sourceCode.getText(property.key)
|
|
494
|
+
}
|
|
469
495
|
module.exports = sortObjects
|
|
@@ -1,5 +1,6 @@
|
|
|
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')
|
|
4
5
|
const createEslintRule = require('../utils/create-eslint-rule.js')
|
|
5
6
|
const getSourceCode = require('../utils/get-source-code.js')
|
|
@@ -16,6 +17,7 @@ let defaultOptions = {
|
|
|
16
17
|
type: 'alphabetical',
|
|
17
18
|
ignoreCase: true,
|
|
18
19
|
locales: 'en-US',
|
|
20
|
+
alphabet: '',
|
|
19
21
|
order: 'asc',
|
|
20
22
|
}
|
|
21
23
|
const sortSwitchCase = createEslintRule.createEslintRule({
|
|
@@ -30,6 +32,7 @@ const sortSwitchCase = createEslintRule.createEslintRule({
|
|
|
30
32
|
settings,
|
|
31
33
|
defaultOptions,
|
|
32
34
|
)
|
|
35
|
+
validateCustomSortConfiguration.validateCustomSortConfiguration(options)
|
|
33
36
|
let sourceCode = getSourceCode.getSourceCode(context)
|
|
34
37
|
let isDiscriminantTrue =
|
|
35
38
|
switchNode.discriminant.type === 'Literal' &&
|
|
@@ -218,6 +221,7 @@ const sortSwitchCase = createEslintRule.createEslintRule({
|
|
|
218
221
|
properties: {
|
|
219
222
|
specialCharacters: commonJsonSchemas.specialCharactersJsonSchema,
|
|
220
223
|
ignoreCase: commonJsonSchemas.ignoreCaseJsonSchema,
|
|
224
|
+
alphabet: commonJsonSchemas.alphabetJsonSchema,
|
|
221
225
|
locales: commonJsonSchemas.localesJsonSchema,
|
|
222
226
|
order: commonJsonSchemas.orderJsonSchema,
|
|
223
227
|
type: commonJsonSchemas.typeJsonSchema,
|
|
@@ -1,6 +1,7 @@
|
|
|
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')
|
|
@@ -28,6 +29,7 @@ let defaultOptions = {
|
|
|
28
29
|
type: 'alphabetical',
|
|
29
30
|
ignoreCase: true,
|
|
30
31
|
locales: 'en-US',
|
|
32
|
+
alphabet: '',
|
|
31
33
|
order: 'asc',
|
|
32
34
|
groups: [],
|
|
33
35
|
}
|
|
@@ -40,6 +42,7 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
40
42
|
settings,
|
|
41
43
|
defaultOptions,
|
|
42
44
|
)
|
|
45
|
+
validateCustomSortConfiguration.validateCustomSortConfiguration(options)
|
|
43
46
|
validateGroupsConfiguration.validateGroupsConfiguration(
|
|
44
47
|
options.groups,
|
|
45
48
|
[
|
|
@@ -144,7 +147,11 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
144
147
|
(options.partitionByComment &&
|
|
145
148
|
isPartitionComment.hasPartitionComment(
|
|
146
149
|
options.partitionByComment,
|
|
147
|
-
getCommentsBefore.getCommentsBefore(
|
|
150
|
+
getCommentsBefore.getCommentsBefore({
|
|
151
|
+
tokenValueToIgnoreBefore: '|',
|
|
152
|
+
node: type,
|
|
153
|
+
sourceCode,
|
|
154
|
+
}),
|
|
148
155
|
)) ||
|
|
149
156
|
(options.partitionByNewLine &&
|
|
150
157
|
lastSortingNode &&
|
|
@@ -245,6 +252,7 @@ const sortUnionTypes = createEslintRule.createEslintRule({
|
|
|
245
252
|
specialCharacters: commonJsonSchemas.specialCharactersJsonSchema,
|
|
246
253
|
newlinesBetween: commonJsonSchemas.newlinesBetweenJsonSchema,
|
|
247
254
|
ignoreCase: commonJsonSchemas.ignoreCaseJsonSchema,
|
|
255
|
+
alphabet: commonJsonSchemas.alphabetJsonSchema,
|
|
248
256
|
locales: commonJsonSchemas.localesJsonSchema,
|
|
249
257
|
groups: commonJsonSchemas.groupsJsonSchema,
|
|
250
258
|
order: commonJsonSchemas.orderJsonSchema,
|
|
@@ -1,6 +1,7 @@
|
|
|
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')
|
|
6
7
|
const isPartitionComment = require('../utils/is-partition-comment.js')
|
|
@@ -23,6 +24,7 @@ let defaultOptions = {
|
|
|
23
24
|
type: 'alphabetical',
|
|
24
25
|
ignoreCase: true,
|
|
25
26
|
locales: 'en-US',
|
|
27
|
+
alphabet: '',
|
|
26
28
|
order: 'asc',
|
|
27
29
|
}
|
|
28
30
|
const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
@@ -37,6 +39,7 @@ const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
|
37
39
|
settings,
|
|
38
40
|
defaultOptions,
|
|
39
41
|
)
|
|
42
|
+
validateCustomSortConfiguration.validateCustomSortConfiguration(options)
|
|
40
43
|
let sourceCode = getSourceCode.getSourceCode(context)
|
|
41
44
|
let eslintDisabledLines = getEslintDisabledLines.getEslintDisabledLines({
|
|
42
45
|
ruleName: context.id,
|
|
@@ -146,7 +149,10 @@ const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
|
146
149
|
(options.partitionByComment &&
|
|
147
150
|
isPartitionComment.hasPartitionComment(
|
|
148
151
|
options.partitionByComment,
|
|
149
|
-
getCommentsBefore.getCommentsBefore(
|
|
152
|
+
getCommentsBefore.getCommentsBefore({
|
|
153
|
+
node: declaration,
|
|
154
|
+
sourceCode,
|
|
155
|
+
}),
|
|
150
156
|
)) ||
|
|
151
157
|
(options.partitionByNewLine &&
|
|
152
158
|
lastSortingNode &&
|
|
@@ -228,6 +234,7 @@ const sortVariableDeclarations = createEslintRule.createEslintRule({
|
|
|
228
234
|
partitionByNewLine: commonJsonSchemas.partitionByNewLineJsonSchema,
|
|
229
235
|
specialCharacters: commonJsonSchemas.specialCharactersJsonSchema,
|
|
230
236
|
ignoreCase: commonJsonSchemas.ignoreCaseJsonSchema,
|
|
237
|
+
alphabet: commonJsonSchemas.alphabetJsonSchema,
|
|
231
238
|
locales: commonJsonSchemas.localesJsonSchema,
|
|
232
239
|
order: commonJsonSchemas.orderJsonSchema,
|
|
233
240
|
type: commonJsonSchemas.typeJsonSchema,
|
|
@@ -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
|