|
| 1 | +# Enforces naming conventions for everything across a codebase (naming-convention) |
| 2 | + |
| 3 | +Enforcing naming conventions helps keep the codebase consistent, and reduces overhead when thinking about how to name a variable. |
| 4 | +Additionally, a well designed style guide can help communicate intent, such as by enforcing all private properties begin with an `_`, and all global-level constants are written in `UPPER_CASE`. |
| 5 | + |
| 6 | +There are many different rules that have existed over time, but they have had the problem of not having enough granularity, meaning it was hard to have a well defined style guide, and most of the time you needed 3 or more rules at once to enforce different conventions, hoping they didn't conflict. |
| 7 | + |
| 8 | +## Rule Details |
| 9 | + |
| 10 | +This rule allows you to enforce conventions for any identifier, using granular selectors to create a fine-grained style guide. |
| 11 | +By default, it enforces nothing. |
| 12 | + |
| 13 | +### Note - this rule only needs type information in specfic cases, detailed below |
| 14 | + |
| 15 | +## Options |
| 16 | + |
| 17 | +This rule accepts an array of objects, with each object describing a different naming convention. |
| 18 | +Each property will be described in detail below. Also see the examples section below for illustrated examples. |
| 19 | + |
| 20 | +```ts |
| 21 | +type Options = { |
| 22 | + // format options |
| 23 | + format: ( |
| 24 | + | 'camelCase' |
| 25 | + | 'strictCamelCase' |
| 26 | + | 'PascalCase' |
| 27 | + | 'StrictPascalCase' |
| 28 | + | 'snake_case' |
| 29 | + | 'UPPER_CASE' |
| 30 | + )[]; |
| 31 | + leadingUnderscore?: 'forbid' | 'allow' | 'require'; |
| 32 | + trailingUnderscore?: 'forbid' | 'allow' | 'require'; |
| 33 | + prefix?: string[]; |
| 34 | + suffix?: string[]; |
| 35 | + |
| 36 | + // selector options |
| 37 | + selector: Selector; |
| 38 | + modifiers?: Modifiers<Selector>[]; |
| 39 | + types?: Types<Selector>[]; |
| 40 | + filter?: string; |
| 41 | +}[]; |
| 42 | + |
| 43 | +const defaultOptions: Options = []; |
| 44 | +``` |
| 45 | + |
| 46 | +### Format Options |
| 47 | + |
| 48 | +Every single selector can have the same set of format options. |
| 49 | +When the format of an identifier is checked, it is checked in the following order: |
| 50 | + |
| 51 | +1. validate leading underscore |
| 52 | +1. validate trailing underscore |
| 53 | +1. validate prefix |
| 54 | +1. validate suffix |
| 55 | +1. validate format |
| 56 | + |
| 57 | +At each step, if the identifier matches the options, it the matching part will be removed. |
| 58 | +For example, if you provide the following formating option: `{ leadingUnderscore: 'allow', prefix: ['I'], format: ['StrictPascalCase'] }`, for the identifier `_IMyInterface`, then the following checks will occur: |
| 59 | + |
| 60 | +1. `name = _IMyInterface` |
| 61 | +1. validate leading underscore - pass |
| 62 | + - Trim leading underscore - `name = IMyInterface` |
| 63 | +1. validate trailing underscore - no check |
| 64 | +1. validate prefix - pass |
| 65 | + - Trim prefix - `name = MyInterface` |
| 66 | +1. validate suffix - no check |
| 67 | +1. validate format - pass |
| 68 | + |
| 69 | +#### `format` |
| 70 | + |
| 71 | +The `format` option defines the allowed formats for the identifier. This option accepts an array of the following values, and the identifier can match any of them: |
| 72 | + |
| 73 | +- `camelCase` - standard camelCase format - no underscores are allowed between characters, and consecutive capitals are allowed (i.e. both `myID` and `myId` are valid). |
| 74 | +- `strictCamelCase` - same as `camelCase`, but consecutive capitals are not allowed (i.e. `myId` is valid, but `myID` is not). |
| 75 | +- `PascalCase` - same as `camelCase`, except the first character must be upper-case. |
| 76 | +- `StrictPascalCase` - same as `strictCamelCase`, except the first character must be upper-case. |
| 77 | +- `snake_case` - standard snake_case format - all characters must be lower-case, and underscores are allowed. |
| 78 | +- `UPPER_CASE` - same as `snake_case`, except all characters must be upper-case. |
| 79 | + |
| 80 | +#### `leadingUnderscore` / `trailingUnderscore` |
| 81 | + |
| 82 | +The `leadingUnderscore` / `trailingUnderscore` options control whether leading/trailing underscores are considered valid. Accepts one of the following values: |
| 83 | + |
| 84 | +- `forbid` - a leading/trailing underscore is not allowed at all. |
| 85 | +- `allow` - existence of a leading/trailing underscore is not explicitly enforced. |
| 86 | +- `require` - a leading/trailing underscores must be included. |
| 87 | + |
| 88 | +#### `prefix` / `suffix` |
| 89 | + |
| 90 | +The `prefix` / `suffix` options control which prefix/suffix strings must exist for the identifier. Accepts an array of strings. |
| 91 | + |
| 92 | +If these are provided, the identifier must start with one of the provided values. For example, if you provide `{ prefix: ['IFace', 'Class', 'Type'] }`, then the following names are valid: `IFaceFoo`, `ClassBar`, `TypeBaz`, but the name `Bang` is not valid, as it contains none of the prefixes. |
| 93 | + |
| 94 | +### Selector Options |
| 95 | + |
| 96 | +The selector options determine which names that the formatting options will apply to. |
| 97 | +Each value for `selector` has a set of `types` and `modifiers` that are allowed to be used with it, which are explained below. |
| 98 | + |
| 99 | +`modifiers` allows you to specify which modifiers to granularly apply to, such as the accessibility (`private`/`public`/`protected`), or if the thing is `static`, etc. The name must match _all_ of the modifiers. For example, if you provide `{ modifiers: ['private', 'static', 'readonly'] }`, then it will only match something that is `private static readonly`, and something that is just `private` will not match. |
| 100 | + |
| 101 | +`types` allows you to specify which types to match. This option supports simple, primitive types only (`boolean`, `string`, `number`, `function`, `array`). This lets you do things like enforce that `boolean` variables are prefixed with a verb. |
| 102 | +**_NOTE - Using this option will require that you lint with type information._** |
| 103 | + |
| 104 | +`filter` accepts a regular expression (anything accepted into `new RegExp(filter)`). It allows you to limit the scope of this configuration to names that match this regex. |
| 105 | + |
| 106 | +#### Allowed Selectors |
| 107 | + |
| 108 | +There are two types of selectors, individual selectors, and grouped selectors. |
| 109 | + |
| 110 | +Individual Selectors match specific, well-defined sets. There is no overlap between each of the individual selectors. |
| 111 | + |
| 112 | +- `variable` - matches any `var` / `let` / `const` variable name. |
| 113 | + - Allowed `modifiers`: none. |
| 114 | + - Allowed `types`: `boolean`, `string`, `number`, `function`, `array`. |
| 115 | +- `function` - matches any named function declaration or named function expression. |
| 116 | + - Allowed `modifiers`: none. |
| 117 | + - Allowed `types`: none. |
| 118 | +- `parameter` - matches any function parameter. Does not match parameter properties. |
| 119 | + - Allowed `modifiers`: none. |
| 120 | + - Allowed `types`: `boolean`, `string`, `number`, `function`, `array`. |
| 121 | +- `property` - matches any object, class, or object type property. Does not match properties that have direct function expression or arrow function expression values. |
| 122 | + - Allowed `modifiers`: `private`, `protected`, `public`, `static`, `readonly`, `abstract`. |
| 123 | + - Allowed `types`: `boolean`, `string`, `number`, `function`, `array`. |
| 124 | +- `parameterProperty` - matches any parameter property. |
| 125 | + - Allowed `modifiers`: `private`, `protected`, `public`, `readonly`. |
| 126 | + - Allowed `types`: `boolean`, `string`, `number`, `function`, `array`. |
| 127 | +- `method` - matches any object, class, or object type method. Also matches properties that have direct function expression or arrow function expression values. Does not match accessors. |
| 128 | + - Allowed `modifiers`: `private`, `protected`, `public`, `static`, `readonly`, `abstract`. |
| 129 | + - Allowed `types`: none. |
| 130 | +- `accessor` - matches any accessor. |
| 131 | + - Allowed `modifiers`: `private`, `protected`, `public`, `static`, `readonly`, `abstract`. |
| 132 | + - Allowed `types`: `boolean`, `string`, `number`, `function`, `array`. |
| 133 | +- `enumMember` - matches any enum member. |
| 134 | + - Allowed `modifiers`: none. |
| 135 | + - Allowed `types`: none. |
| 136 | +- `class` - matches any class declaration. |
| 137 | + - Allowed `modifiers`: `abstract`. |
| 138 | + - Allowed `types`: none. |
| 139 | +- `interface` - matches any interface declaration. |
| 140 | + - Allowed `modifiers`: none. |
| 141 | + - Allowed `types`: none. |
| 142 | +- `typeAlias` - matches any type alias declaration. |
| 143 | + - Allowed `modifiers`: none. |
| 144 | + - Allowed `types`: none. |
| 145 | +- `enum` - matches any enum declaration. |
| 146 | + - Allowed `modifiers`: none. |
| 147 | + - Allowed `types`: none. |
| 148 | +- `typeParameter` - matches any generic type parameter declaration. |
| 149 | + - Allowed `modifiers`: none. |
| 150 | + - Allowed `types`: none. |
| 151 | + |
| 152 | +Group Selectors are provided for convenience, and essentially bundle up sets of individual selectors. |
| 153 | + |
| 154 | +- `default` - matches everything. |
| 155 | + - Allowed `modifiers`: `private`, `protected`, `public`, `static`, `readonly`, `abstract`. |
| 156 | + - Allowed `types`: none. |
| 157 | +- `variableLike` - matches the same as `variable`, `function` and `parameter`. |
| 158 | + - Allowed `modifiers`: none. |
| 159 | + - Allowed `types`: none. |
| 160 | +- `memberLike` - matches the same as `property`, `parameterProperty`, `method`, `accessor`, `enumMember`. |
| 161 | + - Allowed `modifiers`: `private`, `protected`, `public`, `static`, `readonly`, `abstract`. |
| 162 | + - Allowed `types`: none. |
| 163 | +- `typeLike` - matches the same as `class`, `interface`, `typeAlias`, `enum`, `typeParameter`. |
| 164 | + - Allowed `modifiers`: `abstract`. |
| 165 | + - Allowed `types`: none. |
| 166 | + |
| 167 | +The ordering of selectors does not matter. The implementation will automatically sort the selectors to ensure they match from most-specific to least specific. It will keep checking selectors in that order until it finds one that matches the name. |
| 168 | + |
| 169 | +For example, if you provide the following config: |
| 170 | + |
| 171 | +```ts |
| 172 | +[ |
| 173 | + /* 1 */ { selector: 'default', format: ['camelCase'] }, |
| 174 | + /* 2 */ { selector: 'variable', format: ['snake_case'] }, |
| 175 | + /* 3 */ { selector: 'variable', type: ['boolean'], format: ['UPPER_CASE'] }, |
| 176 | + /* 4 */ { selector: 'variableLike', format: ['PascalCase'] }, |
| 177 | +]; |
| 178 | +``` |
| 179 | + |
| 180 | +Then the rule will validate the selectors in the following order: `3`, `2`, `4`, `1`. |
| 181 | + |
| 182 | +## When Not To Use It |
| 183 | + |
| 184 | +If you do not want to enforce naming conventions for anything. |
0 commit comments