Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1db8b8c

Browse files
committed
feat: support simple primitive types
1 parent 910acec commit 1db8b8c

File tree

2 files changed

+168
-18
lines changed

2 files changed

+168
-18
lines changed

packages/eslint-plugin/src/rules/naming-convention.ts

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,9 @@ const FORMAT_OPTIONS_PROPERTIES: JSONSchemaProperties = {
162162
additionalItems: false,
163163
},
164164
};
165-
const TYPE_MODIFIERS_SCHEMA: JSONSchema.JSONSchema4 = {
166-
type: 'array',
167-
items: {
168-
type: 'string',
169-
enum: util.getEnumNames(TypeModifiers),
170-
},
171-
additionalItems: false,
172-
};
173165
function selectorSchema(
174-
type: IndividualAndMetaSelectorsString,
175-
types: boolean,
166+
selectorString: IndividualAndMetaSelectorsString,
167+
allowType: boolean,
176168
modifiers?: ModifiersString[],
177169
): JSONSchema.JSONSchema4[] {
178170
const selector: JSONSchemaProperties = {
@@ -182,7 +174,7 @@ function selectorSchema(
182174
},
183175
selector: {
184176
type: 'string',
185-
enum: [type],
177+
enum: [selectorString],
186178
},
187179
};
188180
if (modifiers && modifiers.length > 0) {
@@ -195,8 +187,15 @@ function selectorSchema(
195187
additionalItems: false,
196188
};
197189
}
198-
if (types) {
199-
selector.types = TYPE_MODIFIERS_SCHEMA;
190+
if (allowType) {
191+
selector.types = {
192+
type: 'array',
193+
items: {
194+
type: 'string',
195+
enum: util.getEnumNames(TypeModifiers),
196+
},
197+
additionalItems: false,
198+
};
200199
}
201200

202201
return [
@@ -671,6 +670,11 @@ function createValidator(
671670
continue;
672671
}
673672

673+
if (!isCorrectType(node, config, context)) {
674+
// is not the correct type
675+
continue;
676+
}
677+
674678
let name: string | null = originalName;
675679

676680
name = validateUnderscore('leading', config, name, node, originalName);
@@ -1012,6 +1016,7 @@ function normalizeOption(option: Selector): NormalizedSelector {
10121016
option.types?.forEach(mod => {
10131017
weight |= TypeModifiers[mod];
10141018
});
1019+
10151020
// give selectors with a filter the _highest_ priority
10161021
if (option.filter) {
10171022
weight |= 1 << 30;
@@ -1035,13 +1040,60 @@ function normalizeOption(option: Selector): NormalizedSelector {
10351040
? MetaSelectors[option.selector]
10361041
: Selectors[option.selector],
10371042
modifiers: option.modifiers?.map(m => Modifiers[m]) ?? null,
1038-
types: option.types?.map(t => TypeModifiers[t]) ?? null,
1043+
types: option.types?.map(m => TypeModifiers[m]) ?? null,
10391044
filter: option.filter !== undefined ? new RegExp(option.filter) : null,
10401045
// calculated ordering weight based on modifiers
10411046
modifierWeight: weight,
10421047
};
10431048
}
10441049

1050+
function isCorrectType(
1051+
node: TSESTree.Node,
1052+
config: NormalizedSelector,
1053+
context: Context,
1054+
): boolean {
1055+
if (config.types === null) {
1056+
return true;
1057+
}
1058+
1059+
const { esTreeNodeToTSNodeMap, program } = util.getParserServices(context);
1060+
const checker = program.getTypeChecker();
1061+
const tsNode = esTreeNodeToTSNodeMap.get(node);
1062+
const type = checker.getTypeAtLocation(tsNode);
1063+
const typeString = checker.typeToString(
1064+
// this will resolve things like true => boolean, 'a' => string and 1 => number
1065+
checker.getWidenedType(checker.getBaseTypeOfLiteralType(type)),
1066+
);
1067+
1068+
for (const allowedType of config.types) {
1069+
switch (allowedType) {
1070+
case TypeModifiers.array:
1071+
// TODO
1072+
break;
1073+
1074+
case TypeModifiers.function:
1075+
// TODO
1076+
break;
1077+
1078+
case TypeModifiers.boolean:
1079+
case TypeModifiers.number:
1080+
case TypeModifiers.string: {
1081+
const allowedTypeString = TypeModifiers[allowedType];
1082+
if (
1083+
typeString === `${allowedTypeString}` ||
1084+
typeString === `${allowedTypeString} | null` ||
1085+
typeString === `${allowedTypeString} | null | undefined`
1086+
) {
1087+
return true;
1088+
}
1089+
break;
1090+
}
1091+
}
1092+
}
1093+
1094+
return false;
1095+
}
1096+
10451097
export {
10461098
MessageIds,
10471099
Options,

packages/eslint-plugin/tests/rules/naming-convention.test.ts

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ import rule, {
66
Selector,
77
selectorTypeToMessageString,
88
} from '../../src/rules/naming-convention';
9-
import { RuleTester } from '../RuleTester';
9+
import { RuleTester, getFixturesRootDir } from '../RuleTester';
1010

1111
const ruleTester = new RuleTester({
1212
parser: '@typescript-eslint/parser',
1313
});
1414

15+
// only need parserOptions for the `type` option tests
16+
const rootDir = getFixturesRootDir();
17+
const parserOptions = {
18+
tsconfigRootDir: rootDir,
19+
project: './tsconfig.json',
20+
};
21+
1522
const formatTestNames: Readonly<Record<
1623
PredefinedFormatsString,
1724
Record<'valid' | 'invalid', string[]>
@@ -91,7 +98,7 @@ function createValidTestCases(cases: Cases): TSESLint.ValidTestCase<Options>[] {
9198
): TSESLint.ValidTestCase<Options> => ({
9299
options: [
93100
{
94-
...(options as Options[0]),
101+
...options,
95102
filter: '[iI]gnored',
96103
},
97104
],
@@ -528,6 +535,97 @@ const cases: Cases = [
528535
];
529536

530537
ruleTester.run('naming-convention', rule, {
531-
valid: createValidTestCases(cases),
532-
invalid: createInvalidTestCases(cases),
538+
valid: [
539+
...createValidTestCases(cases),
540+
{
541+
code: `
542+
declare const string_camelCase: string;
543+
declare const string_camelCase: string | null;
544+
declare const string_camelCase: string | null | undefined;
545+
declare const string_camelCase: 'a' | null | undefined;
546+
declare const string_camelCase: string | 'a' | null | undefined;
547+
548+
declare const number_camelCase: number;
549+
declare const number_camelCase: number | null;
550+
declare const number_camelCase: number | null | undefined;
551+
declare const number_camelCase: 1 | null | undefined;
552+
declare const number_camelCase: number | 2 | null | undefined;
553+
554+
declare const boolean_camelCase: boolean;
555+
declare const boolean_camelCase: boolean | null;
556+
declare const boolean_camelCase: boolean | null | undefined;
557+
declare const boolean_camelCase: true | null | undefined;
558+
declare const boolean_camelCase: false | null | undefined;
559+
declare const boolean_camelCase: true | false | null | undefined;
560+
`,
561+
parserOptions,
562+
options: [
563+
{
564+
selector: 'variable',
565+
types: ['string'],
566+
format: ['camelCase'],
567+
prefix: ['string_'],
568+
},
569+
{
570+
selector: 'variable',
571+
types: ['number'],
572+
format: ['camelCase'],
573+
prefix: ['number_'],
574+
},
575+
{
576+
selector: 'variable',
577+
types: ['boolean'],
578+
format: ['camelCase'],
579+
prefix: ['boolean_'],
580+
},
581+
],
582+
},
583+
],
584+
invalid: [
585+
...createInvalidTestCases(cases),
586+
{
587+
code: `
588+
declare const string_camelCase: string;
589+
declare const string_camelCase: string | null;
590+
declare const string_camelCase: string | null | undefined;
591+
declare const string_camelCase: 'a' | null | undefined;
592+
declare const string_camelCase: string | 'a' | null | undefined;
593+
594+
declare const number_camelCase: number;
595+
declare const number_camelCase: number | null;
596+
declare const number_camelCase: number | null | undefined;
597+
declare const number_camelCase: 1 | null | undefined;
598+
declare const number_camelCase: number | 2 | null | undefined;
599+
600+
declare const boolean_camelCase: boolean;
601+
declare const boolean_camelCase: boolean | null;
602+
declare const boolean_camelCase: boolean | null | undefined;
603+
declare const boolean_camelCase: true | null | undefined;
604+
declare const boolean_camelCase: false | null | undefined;
605+
declare const boolean_camelCase: true | false | null | undefined;
606+
`,
607+
options: [
608+
{
609+
selector: 'variable',
610+
types: ['string'],
611+
format: ['snake_case'],
612+
prefix: ['string_'],
613+
},
614+
{
615+
selector: 'variable',
616+
types: ['number'],
617+
format: ['snake_case'],
618+
prefix: ['number_'],
619+
},
620+
{
621+
selector: 'variable',
622+
types: ['boolean'],
623+
format: ['snake_case'],
624+
prefix: ['boolean_'],
625+
},
626+
],
627+
parserOptions,
628+
errors: Array(16).fill({ messageId: 'doesNotMatchFormat' }),
629+
},
630+
],
533631
});

0 commit comments

Comments
 (0)