diff --git a/docs/content/rules/sort-classes.mdx b/docs/content/rules/sort-classes.mdx index 3a378b69..01394177 100644 --- a/docs/content/rules/sort-classes.mdx +++ b/docs/content/rules/sort-classes.mdx @@ -491,6 +491,7 @@ interface CustomGroupDefinition { selector?: string modifiers?: string[] elementNamePattern?: string + elementValuePattern?: string decoratorNamePattern?: string } ``` @@ -507,6 +508,7 @@ interface CustomGroupBlockDefinition { selector?: string modifiers?: string[] elementNamePattern?: string + elementValuePattern?: string decoratorNamePattern?: string }> } @@ -520,6 +522,7 @@ A class member will match a `CustomGroupBlockDefinition` group if it matches all - `selector`: Filter on the `selector` of the element. - `modifiers`: Filter on the `modifiers` of the element. (All the modifiers of the element must be present in that list) - `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered. +- `elementValuePattern`: Only for non-function properties. If entered, will check that the value of the property matches the pattern entered. - `decoratorNamePattern`: If entered, will check that at least one `decorator` matches the pattern entered. - `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group. - `order`: Overrides the sort order for that custom group diff --git a/rules/sort-classes-utils.ts b/rules/sort-classes-utils.ts index bccbadd4..fcc0f586 100644 --- a/rules/sort-classes-utils.ts +++ b/rules/sort-classes-utils.ts @@ -13,6 +13,7 @@ import { matches } from '../utils/matches' interface CustomGroupMatchesProps { customGroup: SingleCustomGroup | CustomGroupBlock + elementValue: undefined | string matcher: 'minimatch' | 'regex' selectors: Selector[] modifiers: Modifier[] @@ -195,6 +196,20 @@ export const customGroupMatches = (props: CustomGroupMatchesProps): boolean => { } } + if ( + 'elementValuePattern' in props.customGroup && + props.customGroup.elementValuePattern + ) { + let matchesElementValuePattern: boolean = matches( + props.elementValue ?? '', + props.customGroup.elementValuePattern, + props.matcher, + ) + if (!matchesElementValuePattern) { + return false + } + } + if ( 'decoratorNamePattern' in props.customGroup && props.customGroup.decoratorNamePattern diff --git a/rules/sort-classes.ts b/rules/sort-classes.ts index a3571ff2..8ec4d352 100644 --- a/rules/sort-classes.ts +++ b/rules/sort-classes.ts @@ -428,6 +428,7 @@ export default createEslintRule({ } } + let memberValue: undefined | string let modifiers: Modifier[] = [] let selectors: Selector[] = [] if ( @@ -568,6 +569,10 @@ export default createEslintRule({ selectors.push('function-property') } + if (!isFunctionProperty && member.value) { + memberValue = sourceCode.getText(member.value) + } + selectors.push('property') if ( @@ -593,6 +598,7 @@ export default createEslintRule({ customGroupMatches({ customGroup, elementName: name, + elementValue: memberValue, modifiers, selectors, decorators, @@ -619,7 +625,7 @@ export default createEslintRule({ .find(overloadSignatures => overloadSignatures.includes(member)) ?.at(-1) - let value: SortingNodeWithDependencies = { + let sortingNode: SortingNodeWithDependencies = { size: overloadSignatureGroupMember ? rangeToDiff(overloadSignatureGroupMember.range) : rangeToDiff(member.range), @@ -633,7 +639,7 @@ export default createEslintRule({ ), } - accumulator.at(-1)!.push(value) + accumulator.at(-1)!.push(sortingNode) return accumulator }, diff --git a/rules/sort-classes.types.ts b/rules/sort-classes.types.ts index 9fa2996b..031aea5d 100644 --- a/rules/sort-classes.types.ts +++ b/rules/sort-classes.types.ts @@ -156,6 +156,7 @@ interface BaseSingleCustomGroup { type AdvancedSingleCustomGroup = { decoratorNamePattern?: string + elementValuePattern?: string elementNamePattern?: string } & BaseSingleCustomGroup @@ -263,6 +264,10 @@ export const singleCustomGroupJsonSchema: Record = { description: 'Element name pattern filter.', type: 'string', }, + elementValuePattern: { + description: 'Element value pattern filter for properties.', + type: 'string', + }, decoratorNamePattern: { description: 'Decorator name pattern filter.', type: 'string', diff --git a/test/sort-classes.test.ts b/test/sort-classes.test.ts index 7a687d8e..cfbb3831 100644 --- a/test/sort-classes.test.ts +++ b/test/sort-classes.test.ts @@ -6324,6 +6324,58 @@ describe(ruleName, () => { ], }) + ruleTester.run(`${ruleName}: filters on elementValuePattern`, rule, { + valid: [], + invalid: [ + { + code: dedent` + class Class { + a = computed(A) + b = inject(B) + y = inject(Y) + z = computed(Z) + c() {} + } + `, + output: dedent` + class Class { + a = computed(A) + z = computed(Z) + b = inject(B) + y = inject(Y) + c() {} + } + `, + options: [ + { + groups: ['computed', 'inject', 'unknown'], + customGroups: [ + { + groupName: 'inject', + elementValuePattern: 'inject*', + }, + { + groupName: 'computed', + elementValuePattern: 'computed*', + }, + ], + }, + ], + errors: [ + { + messageId: 'unexpectedClassesGroupOrder', + data: { + left: 'y', + leftGroup: 'inject', + right: 'z', + rightGroup: 'computed', + }, + }, + ], + }, + ], + }) + ruleTester.run(`${ruleName}: filters on decoratorNamePattern`, rule, { valid: [], invalid: [ @@ -6775,6 +6827,39 @@ describe(ruleName, () => { }, ) + ruleTester.run( + `${ruleName}: allows to use regex matcher for element values in custom groups with new API`, + rule, + { + valid: [ + { + code: dedent` + class Class { + x = "iHaveFooInMyName" + z = "MeTooIHaveFoo" + a = "a" + b = "b" + } + `, + options: [ + { + type: 'alphabetical', + matcher: 'regex', + groups: ['unknown', 'elementsWithoutFoo'], + customGroups: [ + { + groupName: 'elementsWithoutFoo', + elementValuePattern: '^(?!.*Foo).*$', + }, + ], + }, + ], + }, + ], + invalid: [], + }, + ) + ruleTester.run( `${ruleName}: allows to use regex matcher for decorator names in custom groups with new API`, rule,