-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Rule proposal: Type-based naming rule #722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
(copied from #871) I was actually thinking of opening an issue the other day to suggest something like
Each with optional modifiers (static/instance/abstract, public/protected/private, readonly, etc.), and each with a custom message. Something along the lines of: "id-naming": ["error", {
check: [
{
tokens: ["function", "method"],
match: /camelCaseRegexHere/,
message: "Please, m'kay?"
},
{
tokens: ["private-field"],
match: /^(?!_)/,
message: "We don't do that here.",
},
{
tokens: ["private-backing-field"], // #816 :-)
match: /^_/,
message: "Okay, sure."
}
]
}] (without putting too much thought into it) This rule would then replace:
It seems unnecessary to have so many rules when it's all just about naming of identifiers. |
I was thinking something like this? type BuiltinNamingSchemes =
| 'camelCase'
| 'PascalCase'
| 'snake_case'
| 'Upper_Snake_Case'
| 'CONSTANT_CASE';
const BUILTIN_NAMING_SCHEMES: Record<BuiltinNamingSchemes, RegExp> = {
camelCase: /^[a-z][^_]*$/,
PascalCase: /^[A-Z][^_]*$/,
snake_case: /^[a-z][a-zA-Z_]*$/,
Upper_Snake_Case: /^[A-Z][a-zA-Z]*(_[A-Z][a-zA-Z]*)*$/,
CONSTANT_CASE: /^[A-Z_]+$/,
};
type MatchBase = {
match: BuiltinNamingSchemes | BuiltinNamingSchemes[] | string | string[];
};
type Options = [
{
variables?: MatchBase & {
ignoreObjectDestructuring: boolean;
allowLeadingUnderscore: boolean;
};
functions?: {
functionDeclarationName?: MatchBase;
functionExpressionName?: MatchBase;
arrowFunctionExpressionName?: MatchBase;
arguments?: MatchBase & {
ignoreObjectDestructuring: boolean;
allowLeadingUnderscore: boolean;
};
};
objectProperties?: MatchBase;
class?: {
className?: MatchBase;
privateMemberName?: MatchBase;
protectedMemberName?: MatchBase;
publicMemberName?: MatchBase;
};
interfaces?: MatchBase;
typeDeclaration?: MatchBase;
typeParameterDeclaration?: MatchBase;
objectTypeMember?: MatchBase;
enums?: {
enumName?: MatchBase;
members?: MatchBase;
};
// allow the user to specify any esquery selector
custom?: {
[selector: string]: MatchBase;
};
},
]; Maybe it's too complicated / too flexible? |
Thinking about this, part of me wonders if it makes more sense to split this out into a suite of rules, maybe a new plugin. Just looking at the above config makes me cringe thinking about the implementation complexity.
{
"plugins": ["@typescript-eslint/naming"],
"rules": {
"@typescript-eslint/naming/class-name": ["error", "PascalCase"],
"@typescript-eslint/naming/class-member-name": [
"error",
"camelCase",
{ "modifier": "private", "match": "camelCase", "prefix": "_" },
],
// ...
}
} |
That looks pretty good to me. Some random feedback:
I don't think so, it's possibly even not flexible enough. With solid (conventional) defaults, the user should not have to configure much.
I don't think that it should be necessary to include a plugin for such a basic rule(s).
I can't really comment on implementation complexity (no experience). If a single rule gets too complex, I guess you could have rules like:
... but then you have 6+ rules to configure instead of just one, and you're not able to share configuration – for example, with a single rule, setting |
@bradzacher Have you checked out naming-convention configuration? I think it should work quite well, being very flexible, yet not requiring too many configuration for simpler cases |
@ark120202 That rule looks really good actually, I hadn't seen it before. |
The problem is that this is kind of undetectable without false positives or a dictionary of words because there are valid cases where you want to capitals directly next to each other (IFoo, TypeOfACar). Potentially could be handled by banning 3 or more capitals next to one another, but someone will probably have a case for that.. so might be better to just have a "banned casing" section or something to enforce certain substrings follow certain casing?
The regexes were just examples I cobbled together based on a quick think, I doubt any of them will actually work correctly :)
I see from googling that an argument is the data you pass in to a function, but a parameter is the declaration of the variable in the function.
My question for people is always "what do you gain from having a naming convention for a static readonly abstract class method?" and the answer is usually "nothing, but I want it anyway". At some point I think that you don't need that level of granularity. A lot of naming conventions come from the javascript world - a world without a type checker, or old, old school compiled languages, where your compilation cycles were prohibitively expensive, and IDE tooling was non-existant yet, so you relied on naming to communicate context. In the world of vscode and typescript, IMO 99% of these naming conventions are unnecessary... /rant
That's an interesting rule for sure. Seems to do a lot of what people want. We could model off of it. |
True, but I don't think that these cases occur frequently, and they can often be worked around:
The
I struggle sometimes to convince less than 5 developers that certain conventions make sense – I doubt that you'll be able to convince the authors of 350k public repositories, and countless private ones. 🙂 I usually UPPER_CASE
It seems to be highly configurable, and I really like the inheritance model. One thing that I'd like to see would be a |
I'd like to have a rule that enforces some strict conventions on identifier names. camelcase also allows PascalCase and with id-match it's impossible to enforce this:
It also was a limitation for tslint, so there are few relevant issues:
I'm not really sure what kind of configuration fits this rule (or multiple rules?). For me it would be enough to have a stricter version of camelcase that keeps all classes and functions returning
JSX.Element
in PascalCase and everything else in camelCase, but for some more complex cases it may be worth to have extensible configuration, similar to naming-convention from tslint-consistent-codestyle, which also would cover #515.The text was updated successfully, but these errors were encountered: