UNPKG

20 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22const utils_1 = require("@typescript-eslint/utils");
23const scope_manager_1 = require("@typescript-eslint/scope-manager");
24const util = __importStar(require("../util"));
25const naming_convention_utils_1 = require("./naming-convention-utils");
26// This essentially mirrors ESLint's `camelcase` rule
27// note that that rule ignores leading and trailing underscores and only checks those in the middle of a variable name
28const defaultCamelCaseAllTheThingsConfig = [
29 {
30 selector: 'default',
31 format: ['camelCase'],
32 leadingUnderscore: 'allow',
33 trailingUnderscore: 'allow',
34 },
35 {
36 selector: 'variable',
37 format: ['camelCase', 'UPPER_CASE'],
38 leadingUnderscore: 'allow',
39 trailingUnderscore: 'allow',
40 },
41 {
42 selector: 'typeLike',
43 format: ['PascalCase'],
44 },
45];
46exports.default = util.createRule({
47 name: 'naming-convention',
48 meta: {
49 docs: {
50 description: 'Enforces naming conventions for everything across a codebase',
51 recommended: false,
52 // technically only requires type checking if the user uses "type" modifiers
53 requiresTypeChecking: true,
54 },
55 type: 'suggestion',
56 messages: {
57 unexpectedUnderscore: '{{type}} name `{{name}}` must not have a {{position}} underscore.',
58 missingUnderscore: '{{type}} name `{{name}}` must have {{count}} {{position}} underscore(s).',
59 missingAffix: '{{type}} name `{{name}}` must have one of the following {{position}}es: {{affixes}}',
60 satisfyCustom: '{{type}} name `{{name}}` must {{regexMatch}} the RegExp: {{regex}}',
61 doesNotMatchFormat: '{{type}} name `{{name}}` must match one of the following formats: {{formats}}',
62 doesNotMatchFormatTrimmed: '{{type}} name `{{name}}` trimmed as `{{processedName}}` must match one of the following formats: {{formats}}',
63 },
64 schema: naming_convention_utils_1.SCHEMA,
65 },
66 defaultOptions: defaultCamelCaseAllTheThingsConfig,
67 create(contextWithoutDefaults) {
68 const context = contextWithoutDefaults.options &&
69 contextWithoutDefaults.options.length > 0
70 ? contextWithoutDefaults
71 : // only apply the defaults when the user provides no config
72 Object.setPrototypeOf({
73 options: defaultCamelCaseAllTheThingsConfig,
74 }, contextWithoutDefaults);
75 const validators = (0, naming_convention_utils_1.parseOptions)(context);
76 // getParserServices(context, false) -- dirty hack to work around the docs checker test...
77 const compilerOptions = util
78 .getParserServices(context, true)
79 .program.getCompilerOptions();
80 function handleMember(validator, node, modifiers) {
81 if (!validator) {
82 return;
83 }
84 const key = node.key;
85 if (requiresQuoting(key, compilerOptions.target)) {
86 modifiers.add(naming_convention_utils_1.Modifiers.requiresQuotes);
87 }
88 validator(key, modifiers);
89 }
90 function getMemberModifiers(node) {
91 const modifiers = new Set();
92 if (node.accessibility) {
93 modifiers.add(naming_convention_utils_1.Modifiers[node.accessibility]);
94 }
95 else {
96 modifiers.add(naming_convention_utils_1.Modifiers.public);
97 }
98 if (node.static) {
99 modifiers.add(naming_convention_utils_1.Modifiers.static);
100 }
101 if ('readonly' in node && node.readonly) {
102 modifiers.add(naming_convention_utils_1.Modifiers.readonly);
103 }
104 if (node.type === utils_1.AST_NODE_TYPES.TSAbstractPropertyDefinition ||
105 node.type === utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition) {
106 modifiers.add(naming_convention_utils_1.Modifiers.abstract);
107 }
108 return modifiers;
109 }
110 const unusedVariables = util.collectUnusedVariables(context);
111 function isUnused(name, initialScope = context.getScope()) {
112 var _a;
113 let variable = null;
114 let scope = initialScope;
115 while (scope) {
116 variable = (_a = scope.set.get(name)) !== null && _a !== void 0 ? _a : null;
117 if (variable) {
118 break;
119 }
120 scope = scope.upper;
121 }
122 if (!variable) {
123 return false;
124 }
125 return unusedVariables.has(variable);
126 }
127 function isDestructured(id) {
128 var _a, _b, _c;
129 return (
130 // `const { x }`
131 // does not match `const { x: y }`
132 (((_a = id.parent) === null || _a === void 0 ? void 0 : _a.type) === utils_1.AST_NODE_TYPES.Property && id.parent.shorthand) ||
133 // `const { x = 2 }`
134 // does not match const `{ x: y = 2 }`
135 (((_b = id.parent) === null || _b === void 0 ? void 0 : _b.type) === utils_1.AST_NODE_TYPES.AssignmentPattern &&
136 ((_c = id.parent.parent) === null || _c === void 0 ? void 0 : _c.type) === utils_1.AST_NODE_TYPES.Property &&
137 id.parent.parent.shorthand));
138 }
139 return {
140 // #region variable
141 VariableDeclarator(node) {
142 const validator = validators.variable;
143 if (!validator) {
144 return;
145 }
146 const identifiers = getIdentifiersFromPattern(node.id);
147 const baseModifiers = new Set();
148 const parent = node.parent;
149 if ((parent === null || parent === void 0 ? void 0 : parent.type) === utils_1.AST_NODE_TYPES.VariableDeclaration) {
150 if (parent.kind === 'const') {
151 baseModifiers.add(naming_convention_utils_1.Modifiers.const);
152 }
153 if (isGlobal(context.getScope())) {
154 baseModifiers.add(naming_convention_utils_1.Modifiers.global);
155 }
156 }
157 identifiers.forEach(id => {
158 const modifiers = new Set(baseModifiers);
159 if (isDestructured(id)) {
160 modifiers.add(naming_convention_utils_1.Modifiers.destructured);
161 }
162 if (isExported(parent, id.name, context.getScope())) {
163 modifiers.add(naming_convention_utils_1.Modifiers.exported);
164 }
165 if (isUnused(id.name)) {
166 modifiers.add(naming_convention_utils_1.Modifiers.unused);
167 }
168 validator(id, modifiers);
169 });
170 },
171 // #endregion
172 // #region function
173 'FunctionDeclaration, TSDeclareFunction, FunctionExpression'(node) {
174 const validator = validators.function;
175 if (!validator || node.id === null) {
176 return;
177 }
178 const modifiers = new Set();
179 // functions create their own nested scope
180 const scope = context.getScope().upper;
181 if (isGlobal(scope)) {
182 modifiers.add(naming_convention_utils_1.Modifiers.global);
183 }
184 if (isExported(node, node.id.name, scope)) {
185 modifiers.add(naming_convention_utils_1.Modifiers.exported);
186 }
187 if (isUnused(node.id.name, scope)) {
188 modifiers.add(naming_convention_utils_1.Modifiers.unused);
189 }
190 validator(node.id, modifiers);
191 },
192 // #endregion function
193 // #region parameter
194 'FunctionDeclaration, TSDeclareFunction, TSEmptyBodyFunctionExpression, FunctionExpression, ArrowFunctionExpression'(node) {
195 const validator = validators.parameter;
196 if (!validator) {
197 return;
198 }
199 node.params.forEach(param => {
200 if (param.type === utils_1.AST_NODE_TYPES.TSParameterProperty) {
201 return;
202 }
203 const identifiers = getIdentifiersFromPattern(param);
204 identifiers.forEach(i => {
205 const modifiers = new Set();
206 if (isDestructured(i)) {
207 modifiers.add(naming_convention_utils_1.Modifiers.destructured);
208 }
209 if (isUnused(i.name)) {
210 modifiers.add(naming_convention_utils_1.Modifiers.unused);
211 }
212 validator(i, modifiers);
213 });
214 });
215 },
216 // #endregion parameter
217 // #region parameterProperty
218 TSParameterProperty(node) {
219 const validator = validators.parameterProperty;
220 if (!validator) {
221 return;
222 }
223 const modifiers = getMemberModifiers(node);
224 const identifiers = getIdentifiersFromPattern(node.parameter);
225 identifiers.forEach(i => {
226 validator(i, modifiers);
227 });
228 },
229 // #endregion parameterProperty
230 // #region property
231 ':not(ObjectPattern) > Property[computed = false][kind = "init"][value.type != "ArrowFunctionExpression"][value.type != "FunctionExpression"][value.type != "TSEmptyBodyFunctionExpression"]'(node) {
232 const modifiers = new Set([naming_convention_utils_1.Modifiers.public]);
233 handleMember(validators.objectLiteralProperty, node, modifiers);
234 },
235 ':matches(PropertyDefinition, TSAbstractPropertyDefinition)[computed = false][value.type != "ArrowFunctionExpression"][value.type != "FunctionExpression"][value.type != "TSEmptyBodyFunctionExpression"]'(node) {
236 const modifiers = getMemberModifiers(node);
237 handleMember(validators.classProperty, node, modifiers);
238 },
239 'TSPropertySignature[computed = false]'(node) {
240 const modifiers = new Set([naming_convention_utils_1.Modifiers.public]);
241 if (node.readonly) {
242 modifiers.add(naming_convention_utils_1.Modifiers.readonly);
243 }
244 handleMember(validators.typeProperty, node, modifiers);
245 },
246 // #endregion property
247 // #region method
248 [[
249 'Property[computed = false][kind = "init"][value.type = "ArrowFunctionExpression"]',
250 'Property[computed = false][kind = "init"][value.type = "FunctionExpression"]',
251 'Property[computed = false][kind = "init"][value.type = "TSEmptyBodyFunctionExpression"]',
252 ].join(', ')](node) {
253 const modifiers = new Set([naming_convention_utils_1.Modifiers.public]);
254 handleMember(validators.objectLiteralMethod, node, modifiers);
255 },
256 [[
257 ':matches(PropertyDefinition, TSAbstractPropertyDefinition)[computed = false][value.type = "ArrowFunctionExpression"]',
258 ':matches(PropertyDefinition, TSAbstractPropertyDefinition)[computed = false][value.type = "FunctionExpression"]',
259 ':matches(PropertyDefinition, TSAbstractPropertyDefinition)[computed = false][value.type = "TSEmptyBodyFunctionExpression"]',
260 ':matches(MethodDefinition, TSAbstractMethodDefinition)[computed = false][kind = "method"]',
261 ].join(', ')](node) {
262 const modifiers = getMemberModifiers(node);
263 handleMember(validators.classMethod, node, modifiers);
264 },
265 'TSMethodSignature[computed = false]'(node) {
266 const modifiers = new Set([naming_convention_utils_1.Modifiers.public]);
267 handleMember(validators.typeMethod, node, modifiers);
268 },
269 // #endregion method
270 // #region accessor
271 'Property[computed = false]:matches([kind = "get"], [kind = "set"])'(node) {
272 const modifiers = new Set([naming_convention_utils_1.Modifiers.public]);
273 handleMember(validators.accessor, node, modifiers);
274 },
275 'MethodDefinition[computed = false]:matches([kind = "get"], [kind = "set"])'(node) {
276 const modifiers = getMemberModifiers(node);
277 handleMember(validators.accessor, node, modifiers);
278 },
279 // #endregion accessor
280 // #region enumMember
281 // computed is optional, so can't do [computed = false]
282 'TSEnumMember[computed != true]'(node) {
283 const validator = validators.enumMember;
284 if (!validator) {
285 return;
286 }
287 const id = node.id;
288 const modifiers = new Set();
289 if (requiresQuoting(id, compilerOptions.target)) {
290 modifiers.add(naming_convention_utils_1.Modifiers.requiresQuotes);
291 }
292 validator(id, modifiers);
293 },
294 // #endregion enumMember
295 // #region class
296 'ClassDeclaration, ClassExpression'(node) {
297 const validator = validators.class;
298 if (!validator) {
299 return;
300 }
301 const id = node.id;
302 if (id === null) {
303 return;
304 }
305 const modifiers = new Set();
306 // classes create their own nested scope
307 const scope = context.getScope().upper;
308 if (node.abstract) {
309 modifiers.add(naming_convention_utils_1.Modifiers.abstract);
310 }
311 if (isExported(node, id.name, scope)) {
312 modifiers.add(naming_convention_utils_1.Modifiers.exported);
313 }
314 if (isUnused(id.name, scope)) {
315 modifiers.add(naming_convention_utils_1.Modifiers.unused);
316 }
317 validator(id, modifiers);
318 },
319 // #endregion class
320 // #region interface
321 TSInterfaceDeclaration(node) {
322 const validator = validators.interface;
323 if (!validator) {
324 return;
325 }
326 const modifiers = new Set();
327 const scope = context.getScope();
328 if (isExported(node, node.id.name, scope)) {
329 modifiers.add(naming_convention_utils_1.Modifiers.exported);
330 }
331 if (isUnused(node.id.name, scope)) {
332 modifiers.add(naming_convention_utils_1.Modifiers.unused);
333 }
334 validator(node.id, modifiers);
335 },
336 // #endregion interface
337 // #region typeAlias
338 TSTypeAliasDeclaration(node) {
339 const validator = validators.typeAlias;
340 if (!validator) {
341 return;
342 }
343 const modifiers = new Set();
344 const scope = context.getScope();
345 if (isExported(node, node.id.name, scope)) {
346 modifiers.add(naming_convention_utils_1.Modifiers.exported);
347 }
348 if (isUnused(node.id.name, scope)) {
349 modifiers.add(naming_convention_utils_1.Modifiers.unused);
350 }
351 validator(node.id, modifiers);
352 },
353 // #endregion typeAlias
354 // #region enum
355 TSEnumDeclaration(node) {
356 const validator = validators.enum;
357 if (!validator) {
358 return;
359 }
360 const modifiers = new Set();
361 // enums create their own nested scope
362 const scope = context.getScope().upper;
363 if (isExported(node, node.id.name, scope)) {
364 modifiers.add(naming_convention_utils_1.Modifiers.exported);
365 }
366 if (isUnused(node.id.name, scope)) {
367 modifiers.add(naming_convention_utils_1.Modifiers.unused);
368 }
369 validator(node.id, modifiers);
370 },
371 // #endregion enum
372 // #region typeParameter
373 'TSTypeParameterDeclaration > TSTypeParameter'(node) {
374 const validator = validators.typeParameter;
375 if (!validator) {
376 return;
377 }
378 const modifiers = new Set();
379 const scope = context.getScope();
380 if (isUnused(node.name.name, scope)) {
381 modifiers.add(naming_convention_utils_1.Modifiers.unused);
382 }
383 validator(node.name, modifiers);
384 },
385 // #endregion typeParameter
386 };
387 },
388});
389function getIdentifiersFromPattern(pattern) {
390 const identifiers = [];
391 const visitor = new scope_manager_1.PatternVisitor({}, pattern, id => identifiers.push(id));
392 visitor.visit(pattern);
393 return identifiers;
394}
395function isExported(node, name, scope) {
396 var _a, _b;
397 if (((_a = node === null || node === void 0 ? void 0 : node.parent) === null || _a === void 0 ? void 0 : _a.type) === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration ||
398 ((_b = node === null || node === void 0 ? void 0 : node.parent) === null || _b === void 0 ? void 0 : _b.type) === utils_1.AST_NODE_TYPES.ExportNamedDeclaration) {
399 return true;
400 }
401 if (scope == null) {
402 return false;
403 }
404 const variable = scope.set.get(name);
405 if (variable) {
406 for (const ref of variable.references) {
407 const refParent = ref.identifier.parent;
408 if ((refParent === null || refParent === void 0 ? void 0 : refParent.type) === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration ||
409 (refParent === null || refParent === void 0 ? void 0 : refParent.type) === utils_1.AST_NODE_TYPES.ExportSpecifier) {
410 return true;
411 }
412 }
413 }
414 return false;
415}
416function isGlobal(scope) {
417 if (scope == null) {
418 return false;
419 }
420 return (scope.type === utils_1.TSESLint.Scope.ScopeType.global ||
421 scope.type === utils_1.TSESLint.Scope.ScopeType.module);
422}
423function requiresQuoting(node, target) {
424 const name = node.type === utils_1.AST_NODE_TYPES.Identifier ||
425 node.type === utils_1.AST_NODE_TYPES.PrivateIdentifier
426 ? node.name
427 : `${node.value}`;
428 return util.requiresQuoting(name, target);
429}
430//# sourceMappingURL=naming-convention.js.map
\No newline at end of file