eslint-plugin-strict-eg-rulez 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,455 @@
1
+ # eslint-plugin-eg-rules
2
+
3
+ A collection of custom ESLint rules for React + TypeScript projects. Designed to enforce consistency, readability, and maintainability across frontend codebases.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Usage](#usage)
9
+ - [Rules](#rules)
10
+ - [api-type-suffix](#api-type-suffix)
11
+ - [boolean-prop-naming](#boolean-prop-naming)
12
+ - [component-callback-naming](#component-callback-naming)
13
+ - [functions-naming](#functions-naming)
14
+ - [jsx-event-handler-naming](#jsx-event-handler-naming)
15
+ - [no-test-attrs](#no-test-attrs)
16
+ - [react-component-layout](#react-component-layout)
17
+ - [test-statement-match](#test-statement-match)
18
+ - [Development](#development)
19
+ - [Demo Project](#demo-project)
20
+ - [Adding a New Rule](#adding-a-new-rule)
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install eslint-plugin-eg-rules --save-dev
28
+ ```
29
+
30
+ > **Peer dependency:** ESLint `>=8.0.0` is required.
31
+
32
+ ---
33
+
34
+ ## Usage
35
+
36
+ `eslint.config.mjs` (ESLint Flat Config):
37
+
38
+ ```js
39
+ import egRules from 'eslint-plugin-eg-rules';
40
+
41
+ export default [
42
+ {
43
+ plugins: {
44
+ 'eg-rules': egRules,
45
+ },
46
+ rules: {
47
+ ...egRules.configs.recommended.rules,
48
+ },
49
+ },
50
+ ];
51
+ ```
52
+
53
+ Or configure rules individually:
54
+
55
+ ```js
56
+ import egRules from 'eslint-plugin-eg-rules';
57
+
58
+ export default [
59
+ {
60
+ plugins: { 'eg-rules': egRules },
61
+ rules: {
62
+ 'eg-rules/api-type-suffix': 'error',
63
+ 'eg-rules/boolean-prop-naming': 'warn',
64
+ // ...
65
+ },
66
+ },
67
+ ];
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Rules
73
+
74
+ ### `api-type-suffix`
75
+
76
+ Enforces that TypeScript `interface` and `type` declarations inside `src/apis/` end with an allowed suffix.
77
+
78
+ - **Default suffixes:** `Model`, `Response`, `Request`
79
+ - Consecutive suffixes are not allowed (e.g. `UserRequestModel` ❌)
80
+
81
+ ```ts
82
+ // ✅ Valid
83
+ interface UserModel { ... }
84
+ type LoginResponse = { ... }
85
+
86
+ // ❌ Invalid
87
+ interface User { ... } // Missing suffix
88
+ interface UserRequestModel { ... } // Consecutive suffixes
89
+ ```
90
+
91
+ **Options:**
92
+
93
+ ```json
94
+ ["error", { "suffixes": ["Model", "Response", "Request"] }]
95
+ ```
96
+
97
+ | Option | Type | Default | Description |
98
+ |------------|------------|--------------------------------------|--------------------------|
99
+ | `suffixes` | `string[]` | `["Model", "Response", "Request"]` | Allowed suffixes list |
100
+
101
+ ---
102
+
103
+ ### `boolean-prop-naming`
104
+
105
+ Enforces that boolean props and parameters in `components/`, `hooks/`, and `utils/` folders start with a boolean prefix.
106
+
107
+ - **Default prefixes:** `is`, `has`, `can`, `should`, `will`, `did`, `show`, `hide`
108
+ - Applies to TypeScript-typed booleans: `boolean`, `boolean | null`, `boolean | undefined`, `true | false`
109
+
110
+ ```ts
111
+ // ✅ Valid
112
+ interface ButtonProps {
113
+ isDisabled: boolean;
114
+ hasError?: boolean;
115
+ }
116
+
117
+ // ❌ Invalid
118
+ interface ButtonProps {
119
+ disabled: boolean; // Missing prefix
120
+ }
121
+ ```
122
+
123
+ **Options:**
124
+
125
+ ```json
126
+ ["error", { "prefixes": ["is", "has", "can"] }]
127
+ ```
128
+
129
+ | Option | Type | Default | Description |
130
+ |------------|------------|---------------------------------------------------------------------|-----------------------|
131
+ | `prefixes` | `string[]` | `["is", "has", "can", "should", "will", "did", "show", "hide"]` | Allowed prefixes list |
132
+
133
+ ---
134
+
135
+ ### `component-callback-naming`
136
+
137
+ Enforces that callback function props defined in React component prop types start with `on`.
138
+
139
+ - Also checks for past-tense event names (e.g. `onClicked` → use `onClick`) when `allowPastTense` is `false`
140
+ - Supports `blacklist` and `whitelist` for fine-grained control
141
+
142
+ ```ts
143
+ // ✅ Valid
144
+ interface CardProps {
145
+ onClick: () => void;
146
+ onSubmit: (data: FormData) => void;
147
+ }
148
+
149
+ // ❌ Invalid
150
+ interface CardProps {
151
+ click: () => void; // Missing 'on' prefix
152
+ onClicked: () => void; // Past tense (when allowPastTense: false)
153
+ }
154
+ ```
155
+
156
+ **Options:**
157
+
158
+ ```json
159
+ ["error", {
160
+ "allowPastTense": false,
161
+ "blacklist": ["Clicked"],
162
+ "whitelist": ["onRefetch"]
163
+ }]
164
+ ```
165
+
166
+ | Option | Type | Default | Description |
167
+ |-----------------|------------|---------|----------------------------------------------------|
168
+ | `allowPastTense`| `boolean` | `false` | Allow past tense event suffixes (e.g. `ed`/`d`) |
169
+ | `blacklist` | `string[]` | `[]` | Disallowed suffixes (e.g. `Clicked`) |
170
+ | `whitelist` | `string[]` | `[]` | Names always considered valid (bypass all checks) |
171
+
172
+ ---
173
+
174
+ ### `functions-naming`
175
+
176
+ Enforces that functions are named according to their return type. React components, hooks, and event handlers are ignored.
177
+
178
+ | Return Type | Required Prefix |
179
+ |-------------------------|-------------------------------------|
180
+ | JSX / ReactNode | `render` |
181
+ | `boolean` | `is`, `has`, `will`, `can` |
182
+ | string / number / object / array | `get`, `calculate`, `determine` |
183
+
184
+ ```ts
185
+ // ✅ Valid
186
+ const renderUserCard = () => <Card />;
187
+ const isLoggedIn = (): boolean => true;
188
+ const getUserName = (): string => 'John';
189
+
190
+ // ❌ Invalid
191
+ const userCard = () => <Card />; // Missing 'render'
192
+ const loggedIn = (): boolean => true; // Missing boolean prefix
193
+ const userName = (): string => 'John'; // Missing value prefix
194
+ ```
195
+
196
+ > This rule accepts no configuration options.
197
+
198
+ ---
199
+
200
+ ### `jsx-event-handler-naming`
201
+
202
+ Enforces that locally defined event handlers passed to JSX event props (e.g. `onClick`) start with `handle`. In `strict` mode, the handler name must also end with the event name.
203
+
204
+ ```tsx
205
+ // ✅ Valid
206
+ const handleClick = () => {};
207
+ <Button onClick={handleClick} />
208
+
209
+ // ✅ Valid (strict: true)
210
+ const handleChange = () => {};
211
+ <Input onChange={handleChange} />
212
+
213
+ // ❌ Invalid — missing 'handle' prefix
214
+ const clickAction = () => {};
215
+ <Button onClick={clickAction} />
216
+
217
+ // ❌ Invalid — strict mode: must end with 'Change'
218
+ const handleSubmit = () => {};
219
+ <Input onChange={handleSubmit} />
220
+ ```
221
+
222
+ **Options:**
223
+
224
+ ```json
225
+ ["error", { "strict": true }]
226
+ ```
227
+
228
+ | Option | Type | Default | Description |
229
+ |----------|-----------|---------|----------------------------------------------------------|
230
+ | `strict` | `boolean` | `true` | Handler name must end with the corresponding event name |
231
+
232
+ ---
233
+
234
+ ### `no-test-attrs`
235
+
236
+ Disallow test-only attributes (e.g. `data-testid`, `data-cy`) in non-test source files. These attributes should only appear in test files or test mocks.
237
+
238
+ - **Default forbidden attributes:** `data-testid`, `data-test`, `data-test-id`, `data-cy`, `data-e2e`
239
+ - Automatically ignores files ending with `.test.*`, `.spec.*`, or inside `__tests__/`
240
+
241
+ ```tsx
242
+ // ✅ Valid (in any file)
243
+ <div className="card" id="main" />
244
+
245
+ // ✅ Valid (inside a test file like Button.test.tsx)
246
+ <button data-testid="submit-btn" type="submit" />
247
+
248
+ // ❌ Invalid (inside a normal component like Button.tsx)
249
+ <button data-testid="submit-btn" type="submit" />
250
+ <input data-cy="email-input" />
251
+ ```
252
+
253
+ **Options:**
254
+
255
+ ```json
256
+ ["error", { "attrs": ["data-testid", "data-cy"] }]
257
+ ```
258
+
259
+ | Option | Type | Default | Description |
260
+ |---------|------------|---------------------------------------------------------------------|-----------------------------------------------------|
261
+ | `attrs` | `string[]` | `["data-testid", "data-test", "data-test-id", "data-cy", "data-e2e"]` | List of JSX attribute names considered test-only |
262
+
263
+ ---
264
+
265
+ ### `react-component-layout`
266
+
267
+ Enforces a specific declaration order inside React components. Based on Separation of Concerns (SoC) and MVVM principles. Supports **auto-fix** (`--fix`).
268
+
269
+ **Required order:**
270
+
271
+ | Group | Category | Examples |
272
+ |-------|----------------------|-------------------------------------------------|
273
+ | 0 | Props Destructuring | `const { id, name } = props` |
274
+ | 1 | Priority Hooks | `useLocation`, `useNavigate`, `useTranslation` |
275
+ | 2 | Context Hooks | `useThemeContext`, `useAuthContext` |
276
+ | 3 | State Hooks | `useState`, `useReducer`, `watch` |
277
+ | 4 | Query/Mutation Hooks | `useQuery`, `useMutation` |
278
+ | 5 | Custom Hooks | `useForm`, `useDebounce` |
279
+ | 6 | Effect Hooks | `useEffect`, `useMemo`, `useCallback` |
280
+ | 7 | Utility Functions | `const getLabel = () => ...` |
281
+ | 8 | Event Handlers | `const handleClick = () => ...` |
282
+ | 9 | View Values | `const title = isLoading ? '...' : name` |
283
+ | 10 | Early Returns | `if (!data) return null` |
284
+ | 11 | JSX Return | `return <div>...</div>` |
285
+
286
+ - **Dependency values** (group `-1`) are transparent — they can appear anywhere without triggering order violations.
287
+ - Groups **3** (State), **7** (Utility), and **8** (Handler) must be **contiguous** within themselves.
288
+ - Groups **9** (View Values) and **10** (Early Returns) may be freely swapped with each other.
289
+
290
+ > This rule accepts no configuration options.
291
+
292
+ ---
293
+
294
+ ### `test-statement-match`
295
+
296
+ Enforces naming conventions for `it` and `test` blocks in test files (`.test.*`, `.spec.*`, `__tests__/`).
297
+
298
+ - `it(...)` descriptions must start with `"should "`
299
+ - `test(...)` descriptions must contain a conjunction (`if`, `when`, `while`, etc.)
300
+
301
+ ```ts
302
+ // ✅ Valid
303
+ it('should render the button', () => { ... });
304
+ test('returns null when data is empty', () => { ... });
305
+
306
+ // ❌ Invalid
307
+ it('renders the button', () => { ... }); // Missing 'should'
308
+ test('returns null for empty data', () => { ... }); // No conjunction
309
+ ```
310
+
311
+ **Options:**
312
+
313
+ ```json
314
+ ["error", {
315
+ "conjunctions": ["if", "when", "while", "after", "before"],
316
+ "ignoreTestPatterns": [".*\\.e2e\\.ts$"]
317
+ }]
318
+ ```
319
+
320
+ | Option | Type | Default | Description |
321
+ |----------------------|------------|------------------------------------------------------------|---------------------------------------------|
322
+ | `conjunctions` | `string[]` | `["if", "when", "while", "after", "before", "with", ...]` | Valid conjunctions list |
323
+ | `ignoreTestPatterns` | `string[]` | `[]` | File patterns (regex) to exclude from check |
324
+
325
+ ---
326
+
327
+ ## Development
328
+
329
+ ### Requirements
330
+
331
+ - Node.js 18+
332
+ - npm
333
+
334
+ ### Setup
335
+
336
+ ```bash
337
+ # Install dependencies
338
+ npm install
339
+
340
+ # Build
341
+ npm run build
342
+
343
+ # Run tests
344
+ npm test
345
+
346
+ # Watch mode
347
+ npm test -- --watch
348
+ ```
349
+
350
+ ### Project Structure
351
+
352
+ ```
353
+ eslint-eg-rules/
354
+ ├── src/
355
+ │ ├── index.ts # Plugin entry point; exports rules and configs
356
+ │ ├── rules/
357
+ │ │ ├── api-type-suffix/
358
+ │ │ │ ├── index.ts # Rule implementation
359
+ │ │ │ └── index.test.ts # Tests
360
+ │ │ ├── boolean-prop-naming/
361
+ │ │ ├── component-callback-naming/
362
+ │ │ ├── functions-naming/
363
+ │ │ ├── jsx-event-handler-naming/
364
+ │ │ ├── no-test-attrs/
365
+ │ │ ├── react-component-layout/
366
+ │ │ └── test-statement-match/
367
+ │ └── utils/
368
+ │ └── react-events.ts # Shared event map definitions
369
+ ├── demo/ # Vite + React 18 + TypeScript demo project
370
+ ├── dist/ # Build output (not committed)
371
+ ├── package.json
372
+ └── tsconfig.json
373
+ ```
374
+
375
+ ---
376
+
377
+ ## Demo Project
378
+
379
+ The `demo/` directory is a Vite + React 18 + TypeScript project configured to use only this plugin.
380
+
381
+ ```bash
382
+ # Build the plugin first (from root)
383
+ npm run build
384
+
385
+ # Install demo dependencies
386
+ cd demo && npm install
387
+
388
+ # Run demo dev server
389
+ npm run dev
390
+
391
+ # Run lint check in demo
392
+ npm run lint
393
+ ```
394
+
395
+ > The demo project's ESLint config is independent from the root project's config.
396
+
397
+ ---
398
+
399
+ ## Adding a New Rule
400
+
401
+ 1. Create a new folder under `src/rules/`:
402
+ ```
403
+ src/rules/my-new-rule/
404
+ ├── index.ts # Rule implementation
405
+ └── index.test.ts # Tests
406
+ ```
407
+
408
+ 2. Implement the rule using `@typescript-eslint/utils`:
409
+ ```ts
410
+ import { TSESLint } from '@typescript-eslint/utils';
411
+
412
+ const rule: TSESLint.RuleModule<'myMessage', []> = {
413
+ meta: {
414
+ type: 'suggestion',
415
+ docs: { description: 'Rule description' },
416
+ messages: { myMessage: 'Error message' },
417
+ schema: [],
418
+ },
419
+ defaultOptions: [],
420
+ create(context) {
421
+ return {
422
+ Identifier(node) {
423
+ // ...
424
+ },
425
+ };
426
+ },
427
+ };
428
+
429
+ export default rule;
430
+ ```
431
+
432
+ 3. Register it in `src/index.ts`:
433
+ ```ts
434
+ import myNewRule from './rules/my-new-rule';
435
+
436
+ export const rules = {
437
+ // ...existing rules
438
+ 'my-new-rule': myNewRule,
439
+ };
440
+
441
+ export const configs = {
442
+ recommended: {
443
+ rules: {
444
+ // ...
445
+ 'eg-rules/my-new-rule': 'error',
446
+ },
447
+ },
448
+ };
449
+ ```
450
+
451
+ 4. Build and test:
452
+ ```bash
453
+ npm run build
454
+ cd demo && npm run lint
455
+ ```
@@ -0,0 +1,40 @@
1
+ export declare const rules: {
2
+ 'api-type-suffix': import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"invalidSuffix" | "consecutiveSuffix", [{
3
+ suffixes?: string[];
4
+ }], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
5
+ 'component-callback-naming': import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"invalidCallbackProp" | "pastTenseEvent" | "blacklistedEvent", [{
6
+ allowPastTense?: boolean;
7
+ blacklist?: string[];
8
+ whitelist?: string[];
9
+ }], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
10
+ 'jsx-event-handler-naming': import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingHandlePrefix" | "strictMismatch", [{
11
+ strict?: boolean;
12
+ }], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
13
+ 'functions-naming': import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingRenderPrefix" | "missingBooleanPrefix" | "missingValuePrefix", [], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
14
+ 'boolean-prop-naming': import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingPrefix", [{
15
+ prefixes?: string[];
16
+ }], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
17
+ 'test-statement-match': import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"itMustStartWithShould" | "testMustContainConjunction", [{
18
+ conjunctions?: string[];
19
+ ignoreTestPatterns?: string[];
20
+ }], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
21
+ 'react-component-layout': import("eslint").Rule.RuleModule;
22
+ 'no-test-attrs': import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noTestAttr", [{
23
+ attrs?: string[];
24
+ }], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
25
+ };
26
+ export declare const configs: {
27
+ recommended: {
28
+ plugins: string[];
29
+ rules: {
30
+ 'eg-rules/api-type-suffix': string;
31
+ 'eg-rules/component-callback-naming': string;
32
+ 'eg-rules/jsx-event-handler-naming': string;
33
+ 'eg-rules/functions-naming': string;
34
+ 'eg-rules/boolean-prop-naming': string;
35
+ 'eg-rules/test-statement-match': string;
36
+ 'eg-rules/react-component-layout': string;
37
+ 'eg-rules/no-test-attrs': string;
38
+ };
39
+ };
40
+ };
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.configs = exports.rules = void 0;
7
+ const api_type_suffix_1 = __importDefault(require("./rules/api-type-suffix"));
8
+ const component_callback_naming_1 = __importDefault(require("./rules/component-callback-naming"));
9
+ const jsx_event_handler_naming_1 = __importDefault(require("./rules/jsx-event-handler-naming"));
10
+ const functions_naming_1 = __importDefault(require("./rules/functions-naming"));
11
+ const boolean_prop_naming_1 = __importDefault(require("./rules/boolean-prop-naming"));
12
+ const test_statement_match_1 = __importDefault(require("./rules/test-statement-match"));
13
+ const react_component_layout_1 = require("./rules/react-component-layout");
14
+ const no_test_attrs_1 = __importDefault(require("./rules/no-test-attrs"));
15
+ exports.rules = {
16
+ 'api-type-suffix': api_type_suffix_1.default,
17
+ 'component-callback-naming': component_callback_naming_1.default,
18
+ 'jsx-event-handler-naming': jsx_event_handler_naming_1.default,
19
+ 'functions-naming': functions_naming_1.default,
20
+ 'boolean-prop-naming': boolean_prop_naming_1.default,
21
+ 'test-statement-match': test_statement_match_1.default,
22
+ 'react-component-layout': react_component_layout_1.reactComponentLayoutRule,
23
+ 'no-test-attrs': no_test_attrs_1.default,
24
+ };
25
+ exports.configs = {
26
+ recommended: {
27
+ plugins: ['eg-rules'],
28
+ rules: {
29
+ 'eg-rules/api-type-suffix': 'error',
30
+ 'eg-rules/component-callback-naming': 'error',
31
+ 'eg-rules/jsx-event-handler-naming': 'error',
32
+ 'eg-rules/functions-naming': 'error',
33
+ 'eg-rules/boolean-prop-naming': 'error',
34
+ 'eg-rules/test-statement-match': 'error',
35
+ 'eg-rules/react-component-layout': 'warn',
36
+ 'eg-rules/no-test-attrs': 'error',
37
+ },
38
+ },
39
+ };
@@ -0,0 +1,7 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ type Options = [{
3
+ suffixes?: string[];
4
+ }];
5
+ type MessageIds = 'invalidSuffix' | 'consecutiveSuffix';
6
+ declare const rule: TSESLint.RuleModule<MessageIds, Options>;
7
+ export default rule;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const rule = {
4
+ defaultOptions: [{}],
5
+ meta: {
6
+ type: 'suggestion',
7
+ docs: {
8
+ description: 'Enforce specific suffixes for types/interfaces in the API folder',
9
+ },
10
+ messages: {
11
+ invalidSuffix: "Type/Interface '{{name}}' in the API folder must end with one of the allowed suffixes: {{suffixes}}.",
12
+ consecutiveSuffix: "Type/Interface '{{name}}' cannot have consecutive suffixes ('{{consecutive}}' followed by '{{matched}}').",
13
+ },
14
+ schema: [
15
+ {
16
+ type: 'object',
17
+ properties: {
18
+ suffixes: {
19
+ type: 'array',
20
+ items: {
21
+ type: 'string',
22
+ },
23
+ minItems: 1,
24
+ },
25
+ },
26
+ additionalProperties: false,
27
+ },
28
+ ],
29
+ },
30
+ create(context) {
31
+ const filename = context.filename ?? context.getFilename();
32
+ const isApiFolder = filename.includes('/src/apis/') || filename.includes('\\src\\apis\\');
33
+ // If it's not in the API folder, we don't enforce anything
34
+ if (!isApiFolder) {
35
+ return {};
36
+ }
37
+ const options = context.options[0] || {};
38
+ const suffixes = options.suffixes && options.suffixes.length > 0
39
+ ? options.suffixes
40
+ : ['Model', 'Response', 'Request'];
41
+ function checkNode(node, name) {
42
+ const matchedSuffix = suffixes.find((s) => name.endsWith(s));
43
+ if (!matchedSuffix) {
44
+ context.report({
45
+ node,
46
+ messageId: 'invalidSuffix',
47
+ data: {
48
+ name,
49
+ suffixes: suffixes.join(', '),
50
+ },
51
+ });
52
+ return;
53
+ }
54
+ const remainingName = name.slice(0, -matchedSuffix.length);
55
+ const consecutiveSuffix = suffixes.find((s) => remainingName.endsWith(s));
56
+ if (consecutiveSuffix) {
57
+ context.report({
58
+ node,
59
+ messageId: 'consecutiveSuffix',
60
+ data: {
61
+ name,
62
+ consecutive: consecutiveSuffix,
63
+ matched: matchedSuffix,
64
+ },
65
+ });
66
+ }
67
+ }
68
+ return {
69
+ TSInterfaceDeclaration(node) {
70
+ checkNode(node.id, node.id.name);
71
+ },
72
+ TSTypeAliasDeclaration(node) {
73
+ checkNode(node.id, node.id.name);
74
+ },
75
+ };
76
+ },
77
+ };
78
+ exports.default = rule;
@@ -0,0 +1,7 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ type MessageIds = 'missingPrefix';
3
+ type Options = [{
4
+ prefixes?: string[];
5
+ }];
6
+ declare const rule: TSESLint.RuleModule<MessageIds, Options>;
7
+ export default rule;