@blumintinc/eslint-plugin-blumint 1.18.16 → 1.19.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.
@@ -0,0 +1,571 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.enforceSingleExportedUnitPerFile = void 0;
27
+ const path = __importStar(require("path"));
28
+ const utils_1 = require("@typescript-eslint/utils");
29
+ const createRule_1 = require("../utils/createRule");
30
+ const ASTHelpers_1 = require("../utils/ASTHelpers");
31
+ /**
32
+ * React heritage names that make a `class` a component rather than a plain
33
+ * class. Deeper indirection (aliased imports, HOC-produced base classes) is an
34
+ * acceptable false negative per the false-negative bias.
35
+ */
36
+ const REACT_COMPONENT_BASES = new Set([
37
+ 'Component',
38
+ 'PureComponent',
39
+ 'React.Component',
40
+ 'React.PureComponent',
41
+ ]);
42
+ /**
43
+ * Call expressions that always produce a React component from their (unwrapped)
44
+ * argument. Any of these as the initializer of a PascalCase const marks it a
45
+ * component unit regardless of whether the wrapped function is locally visible.
46
+ */
47
+ const REACT_COMPONENT_WRAPPERS = new Set([
48
+ 'memo',
49
+ 'React.memo',
50
+ 'forwardRef',
51
+ 'React.forwardRef',
52
+ ]);
53
+ /**
54
+ * Call expressions whose PascalCase result is deliberately NOT a component
55
+ * (a React context object is PascalCase by convention but never renders).
56
+ */
57
+ const NON_COMPONENT_FACTORIES = new Set([
58
+ 'createContext',
59
+ 'React.createContext',
60
+ ]);
61
+ /**
62
+ * A React component export must be PascalCase. This deliberately excludes
63
+ * SCREAMING_SNAKE_CASE constants (underscores) and hooks (`/^use[A-Z]/` starts
64
+ * lowercase), so neither can ever be miscounted as a component.
65
+ */
66
+ function isComponentName(name) {
67
+ return /^[A-Z][A-Za-z0-9]*$/.test(name);
68
+ }
69
+ /**
70
+ * Mirrors `prefer-utility-function-own-file`'s exemption model (test/spec, mock,
71
+ * declaration files) minus its `/types/` carve-out, which this rule does not use.
72
+ * `*.stories.tsx` is intentionally NOT exempt in v1 — see the rule docs.
73
+ */
74
+ function isExemptFile(filename) {
75
+ if (!filename)
76
+ return false;
77
+ const normalized = filename.replace(/\\/g, '/');
78
+ if (/\.(test|spec)\.(tsx?|jsx?)$/.test(normalized))
79
+ return true;
80
+ if (/\/__mocks__\//.test(normalized))
81
+ return true;
82
+ if (/\.d\.ts$/.test(normalized))
83
+ return true;
84
+ return false;
85
+ }
86
+ /**
87
+ * Strips TypeScript-only expression wrappers (`as`, `satisfies`, `!`, `<T>x`) so
88
+ * the underlying function/call/class expression can be inspected directly.
89
+ */
90
+ function unwrapExpression(expr) {
91
+ let node = expr;
92
+ while (node &&
93
+ (node.type === utils_1.AST_NODE_TYPES.TSAsExpression ||
94
+ node.type === utils_1.AST_NODE_TYPES.TSSatisfiesExpression ||
95
+ node.type === utils_1.AST_NODE_TYPES.TSNonNullExpression ||
96
+ node.type === utils_1.AST_NODE_TYPES.TSTypeAssertion ||
97
+ node.type === 'ParenthesizedExpression')) {
98
+ node = node.expression;
99
+ }
100
+ return node ?? null;
101
+ }
102
+ function isFunctionNode(node) {
103
+ return (node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
104
+ node.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
105
+ node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration);
106
+ }
107
+ /**
108
+ * Resolves a call's callee to a dotted name (`memo`, `React.memo`, ...). Returns
109
+ * undefined for callees that are not a plain identifier or `a.b` member access
110
+ * (e.g. a curried `connect(x)(Y)` where the callee is itself a call).
111
+ */
112
+ function getCalleeName(callee) {
113
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier) {
114
+ return callee.name;
115
+ }
116
+ if (callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
117
+ !callee.computed &&
118
+ callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
119
+ callee.property.type === utils_1.AST_NODE_TYPES.Identifier) {
120
+ return `${callee.object.name}.${callee.property.name}`;
121
+ }
122
+ return undefined;
123
+ }
124
+ /**
125
+ * True when a generic (non-`memo`/`forwardRef`) HOC call is applied to something
126
+ * component-like: an inline JSX-returning function, or a PascalCase identifier
127
+ * (a component reference such as `withDatePickerEdit(DatePicker)`). Recurses
128
+ * through nested call arguments but never into function bodies.
129
+ */
130
+ function callHasComponentArgument(call) {
131
+ for (const arg of call.arguments) {
132
+ if (arg.type === utils_1.AST_NODE_TYPES.SpreadElement)
133
+ continue;
134
+ const inner = unwrapExpression(arg);
135
+ if (!inner)
136
+ continue;
137
+ if (isFunctionNode(inner) && ASTHelpers_1.ASTHelpers.returnsJSX(inner)) {
138
+ return true;
139
+ }
140
+ if (inner.type === utils_1.AST_NODE_TYPES.Identifier &&
141
+ isComponentName(inner.name)) {
142
+ return true;
143
+ }
144
+ if (inner.type === utils_1.AST_NODE_TYPES.CallExpression &&
145
+ callHasComponentArgument(inner)) {
146
+ return true;
147
+ }
148
+ }
149
+ return false;
150
+ }
151
+ /**
152
+ * True when a call expression produces a React component: a known React wrapper
153
+ * (`memo`/`forwardRef`), or a generic HOC applied to a component-like argument.
154
+ * Known non-component factories (`createContext`) are excluded up front.
155
+ */
156
+ function callProducesComponent(call) {
157
+ const calleeName = getCalleeName(call.callee);
158
+ if (calleeName && NON_COMPONENT_FACTORIES.has(calleeName)) {
159
+ return false;
160
+ }
161
+ if (calleeName && REACT_COMPONENT_WRAPPERS.has(calleeName)) {
162
+ return true;
163
+ }
164
+ return callHasComponentArgument(call);
165
+ }
166
+ function getSuperClassName(node) {
167
+ const superClass = node.superClass;
168
+ if (!superClass)
169
+ return undefined;
170
+ if (superClass.type === utils_1.AST_NODE_TYPES.Identifier) {
171
+ return superClass.name;
172
+ }
173
+ if (superClass.type === utils_1.AST_NODE_TYPES.MemberExpression &&
174
+ !superClass.computed &&
175
+ superClass.object.type === utils_1.AST_NODE_TYPES.Identifier &&
176
+ superClass.property.type === utils_1.AST_NODE_TYPES.Identifier) {
177
+ return `${superClass.object.name}.${superClass.property.name}`;
178
+ }
179
+ return undefined;
180
+ }
181
+ function classifyClass(node) {
182
+ const superName = getSuperClassName(node);
183
+ if (superName && REACT_COMPONENT_BASES.has(superName)) {
184
+ return 'component';
185
+ }
186
+ return 'class';
187
+ }
188
+ /**
189
+ * Classifies an initializer/expression. `name` is the binding name for the
190
+ * PascalCase gate, or null for anonymous default exports (which bypass the gate
191
+ * because they are inherently the file's primary export).
192
+ */
193
+ function classifyExpression(expr, name) {
194
+ const inner = unwrapExpression(expr);
195
+ if (!inner)
196
+ return 'neither';
197
+ const nameOk = name === null ? true : isComponentName(name);
198
+ if (isFunctionNode(inner)) {
199
+ return nameOk && ASTHelpers_1.ASTHelpers.returnsJSX(inner) ? 'component' : 'neither';
200
+ }
201
+ if (inner.type === utils_1.AST_NODE_TYPES.ClassExpression) {
202
+ return classifyClass(inner);
203
+ }
204
+ if (inner.type === utils_1.AST_NODE_TYPES.CallExpression) {
205
+ if (!nameOk)
206
+ return 'neither';
207
+ return callProducesComponent(inner) ? 'component' : 'neither';
208
+ }
209
+ return 'neither';
210
+ }
211
+ /**
212
+ * Collects identifier names referenced as (recursive) call arguments — the basis
213
+ * of the derived-wrapper collapse. Nested call arguments are followed
214
+ * (`memo(forwardRef(X))`), but function bodies are never entered (rendering a
215
+ * sibling in JSX is not deriving from it).
216
+ */
217
+ function collectCallArgumentIdentifiers(call) {
218
+ const ids = [];
219
+ for (const arg of call.arguments) {
220
+ if (arg.type === utils_1.AST_NODE_TYPES.SpreadElement)
221
+ continue;
222
+ const inner = unwrapExpression(arg);
223
+ if (!inner)
224
+ continue;
225
+ if (inner.type === utils_1.AST_NODE_TYPES.Identifier) {
226
+ ids.push(inner.name);
227
+ }
228
+ else if (inner.type === utils_1.AST_NODE_TYPES.CallExpression) {
229
+ ids.push(...collectCallArgumentIdentifiers(inner));
230
+ }
231
+ }
232
+ return ids;
233
+ }
234
+ /**
235
+ * True when a class body has no member other than a constructor (an empty body
236
+ * qualifies vacuously). Any property, getter/setter, method, index signature, or
237
+ * static block disqualifies it — that is a real abstraction, not a trivial
238
+ * subclass. Purely syntactic per Edge Case 6.
239
+ */
240
+ function isConstructorOnlyClass(node) {
241
+ return node.body.body.every((member) => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
242
+ member.kind === 'constructor');
243
+ }
244
+ exports.enforceSingleExportedUnitPerFile = (0, createRule_1.createRule)({
245
+ name: 'enforce-single-exported-unit-per-file',
246
+ meta: {
247
+ type: 'suggestion',
248
+ docs: {
249
+ description: 'Enforce that a .tsx/.jsx file exports at most one React component and any file exports at most one class',
250
+ recommended: 'error',
251
+ },
252
+ schema: [],
253
+ messages: {
254
+ multipleExportedComponents: 'File exports {{count}} React components ({{names}}). Limit each .tsx file to one exported component: extract "{{name}}" into its own file, or parameterize sibling variants into a single component.',
255
+ multipleExportedClasses: 'File exports {{count}} classes ({{names}}). Limit each file to one exported class: extract "{{name}}" into its own file.',
256
+ },
257
+ },
258
+ defaultOptions: [],
259
+ create(context) {
260
+ const filename = context.getFilename();
261
+ if (isExemptFile(filename))
262
+ return {};
263
+ const ext = path.extname(filename);
264
+ const isComponentFile = ext === '.tsx' || ext === '.jsx';
265
+ // All top-level class declarations by name — used for in-file base-chain
266
+ // resolution in the error-hierarchy exemption (a base need not be exported).
267
+ const allClassDecls = new Map();
268
+ const declByName = new Map();
269
+ const exportedNames = new Set();
270
+ const anonymousDefaults = [];
271
+ function isTopLevel(node) {
272
+ const parent = node.parent;
273
+ return (parent?.type === utils_1.AST_NODE_TYPES.Program ||
274
+ parent?.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration ||
275
+ parent?.type === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration);
276
+ }
277
+ function isExportedParent(node) {
278
+ const parent = node.parent;
279
+ return (parent?.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration ||
280
+ parent?.type === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration);
281
+ }
282
+ return {
283
+ ClassDeclaration(node) {
284
+ if (!isTopLevel(node) || !node.id)
285
+ return;
286
+ const name = node.id.name;
287
+ allClassDecls.set(name, node);
288
+ declByName.set(name, { name, node, kind: 'class', classNode: node });
289
+ if (isExportedParent(node))
290
+ exportedNames.add(name);
291
+ },
292
+ FunctionDeclaration(node) {
293
+ if (!isTopLevel(node) || !node.id)
294
+ return;
295
+ const name = node.id.name;
296
+ declByName.set(name, { name, node, kind: 'function', fnNode: node });
297
+ if (isExportedParent(node))
298
+ exportedNames.add(name);
299
+ },
300
+ VariableDeclaration(node) {
301
+ const parent = node.parent;
302
+ const topLevel = parent?.type === utils_1.AST_NODE_TYPES.Program ||
303
+ parent?.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration;
304
+ if (!topLevel)
305
+ return;
306
+ const exported = parent?.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration;
307
+ for (const declarator of node.declarations) {
308
+ if (declarator.id.type !== utils_1.AST_NODE_TYPES.Identifier)
309
+ continue;
310
+ const name = declarator.id.name;
311
+ declByName.set(name, {
312
+ name,
313
+ node: declarator,
314
+ kind: 'variable',
315
+ init: declarator.init,
316
+ });
317
+ if (exported)
318
+ exportedNames.add(name);
319
+ }
320
+ },
321
+ ExportNamedDeclaration(node) {
322
+ // `export { X } from './x'` / `export * from` re-surface declarations
323
+ // from other files — zero new units here.
324
+ if (node.source)
325
+ return;
326
+ if (node.declaration)
327
+ return;
328
+ for (const specifier of node.specifiers) {
329
+ if (specifier.local.type === utils_1.AST_NODE_TYPES.Identifier) {
330
+ exportedNames.add(specifier.local.name);
331
+ }
332
+ }
333
+ },
334
+ ExportDefaultDeclaration(node) {
335
+ const decl = node.declaration;
336
+ if (decl.type === utils_1.AST_NODE_TYPES.Identifier) {
337
+ exportedNames.add(decl.name);
338
+ return;
339
+ }
340
+ if (decl.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
341
+ decl.type === utils_1.AST_NODE_TYPES.ClassDeclaration) {
342
+ // Named default declarations are collected by their own visitors;
343
+ // only anonymous ones need a synthetic unit here.
344
+ if (!decl.id) {
345
+ if (decl.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
346
+ anonymousDefaults.push({ node, fnNode: decl });
347
+ }
348
+ }
349
+ return;
350
+ }
351
+ if (decl.type === utils_1.AST_NODE_TYPES.ClassExpression) {
352
+ anonymousDefaults.push({ node, classNode: decl });
353
+ return;
354
+ }
355
+ anonymousDefaults.push({ node, expr: decl });
356
+ },
357
+ 'Program:exit'() {
358
+ const units = [];
359
+ for (const name of exportedNames) {
360
+ const decl = declByName.get(name);
361
+ if (!decl)
362
+ continue;
363
+ let classification = 'neither';
364
+ let callArgIdentifiers = [];
365
+ if (decl.kind === 'class' && decl.classNode) {
366
+ classification = classifyClass(decl.classNode);
367
+ }
368
+ else if (decl.kind === 'function' && decl.fnNode) {
369
+ classification =
370
+ isComponentName(name) && ASTHelpers_1.ASTHelpers.returnsJSX(decl.fnNode)
371
+ ? 'component'
372
+ : 'neither';
373
+ }
374
+ else {
375
+ classification = classifyExpression(decl.init, name);
376
+ const inner = unwrapExpression(decl.init);
377
+ // Only a derived COMPONENT wrapper collapses into its source; a
378
+ // non-component call (a factory, config builder) never does.
379
+ if (classification === 'component' &&
380
+ inner &&
381
+ inner.type === utils_1.AST_NODE_TYPES.CallExpression) {
382
+ callArgIdentifiers = collectCallArgumentIdentifiers(inner);
383
+ }
384
+ }
385
+ units.push({
386
+ id: name,
387
+ name,
388
+ node: decl.node,
389
+ classification,
390
+ callArgIdentifiers,
391
+ });
392
+ }
393
+ let anonIndex = 0;
394
+ for (const anon of anonymousDefaults) {
395
+ let classification = 'neither';
396
+ let callArgIdentifiers = [];
397
+ if (anon.fnNode) {
398
+ classification = ASTHelpers_1.ASTHelpers.returnsJSX(anon.fnNode)
399
+ ? 'component'
400
+ : 'neither';
401
+ }
402
+ else if (anon.classNode) {
403
+ classification = classifyClass(anon.classNode);
404
+ }
405
+ else if (anon.expr) {
406
+ classification = classifyExpression(anon.expr, null);
407
+ const inner = unwrapExpression(anon.expr);
408
+ if (classification === 'component' &&
409
+ inner &&
410
+ inner.type === utils_1.AST_NODE_TYPES.CallExpression) {
411
+ callArgIdentifiers = collectCallArgumentIdentifiers(inner);
412
+ }
413
+ }
414
+ units.push({
415
+ id: `\0default${anonIndex++}`,
416
+ name: 'default',
417
+ node: anon.node,
418
+ classification,
419
+ callArgIdentifiers,
420
+ });
421
+ }
422
+ if (units.length === 0)
423
+ return;
424
+ // Union-find over units for the derived-wrapper collapse.
425
+ const parent = new Map();
426
+ for (const unit of units)
427
+ parent.set(unit.id, unit.id);
428
+ const find = (id) => {
429
+ let root = id;
430
+ let next = parent.get(root) ?? root;
431
+ while (next !== root) {
432
+ root = next;
433
+ next = parent.get(root) ?? root;
434
+ }
435
+ let cur = id;
436
+ let curParent = parent.get(cur) ?? cur;
437
+ while (curParent !== root) {
438
+ parent.set(cur, root);
439
+ cur = curParent;
440
+ curParent = parent.get(cur) ?? cur;
441
+ }
442
+ return root;
443
+ };
444
+ const union = (a, b) => {
445
+ const ra = find(a);
446
+ const rb = find(b);
447
+ if (ra !== rb)
448
+ parent.set(ra, rb);
449
+ };
450
+ const unitIds = new Set(units.map((u) => u.id));
451
+ for (const unit of units) {
452
+ for (const refName of unit.callArgIdentifiers) {
453
+ if (refName !== unit.id && unitIds.has(refName)) {
454
+ union(unit.id, refName);
455
+ }
456
+ }
457
+ }
458
+ // Group units into their collapsed representation.
459
+ const groupsMap = new Map();
460
+ for (const unit of units) {
461
+ const root = find(unit.id);
462
+ const members = groupsMap.get(root) ?? [];
463
+ members.push(unit);
464
+ groupsMap.set(root, members);
465
+ }
466
+ const groups = [];
467
+ for (const members of groupsMap.values()) {
468
+ const classification = members.some((m) => m.classification === 'component')
469
+ ? 'component'
470
+ : members.some((m) => m.classification === 'class')
471
+ ? 'class'
472
+ : 'neither';
473
+ // Representative: the last-declared member (by convention the public
474
+ // wrapper, e.g. `Logo` over `LogoUnmemoized`).
475
+ const rep = members.reduce((latest, m) => m.node.range[0] > latest.node.range[0] ? m : latest);
476
+ const classNodes = [];
477
+ for (const m of members) {
478
+ const decl = declByName.get(m.id);
479
+ if (decl?.kind === 'class' && decl.classNode) {
480
+ classNodes.push(decl.classNode);
481
+ }
482
+ }
483
+ groups.push({
484
+ classification,
485
+ repName: rep.name,
486
+ repNode: rep.node,
487
+ position: rep.node.range[0],
488
+ classNodes,
489
+ });
490
+ }
491
+ const componentGroups = groups
492
+ .filter((g) => g.classification === 'component')
493
+ .sort((a, b) => a.position - b.position);
494
+ const classGroups = groups
495
+ .filter((g) => g.classification === 'class')
496
+ .sort((a, b) => a.position - b.position);
497
+ if (isComponentFile && componentGroups.length >= 2) {
498
+ const names = componentGroups.map((g) => g.repName).join(', ');
499
+ for (const group of componentGroups.slice(1)) {
500
+ context.report({
501
+ node: group.repNode,
502
+ messageId: 'multipleExportedComponents',
503
+ data: {
504
+ count: componentGroups.length,
505
+ names,
506
+ name: group.repName,
507
+ },
508
+ });
509
+ }
510
+ }
511
+ if (classGroups.length >= 2) {
512
+ const exportedClassNodes = classGroups.flatMap((g) => g.classNodes);
513
+ if (!isExemptErrorHierarchy(exportedClassNodes, allClassDecls)) {
514
+ const names = classGroups.map((g) => g.repName).join(', ');
515
+ for (const group of classGroups.slice(1)) {
516
+ context.report({
517
+ node: group.repNode,
518
+ messageId: 'multipleExportedClasses',
519
+ data: {
520
+ count: classGroups.length,
521
+ names,
522
+ name: group.repName,
523
+ },
524
+ });
525
+ }
526
+ }
527
+ }
528
+ },
529
+ };
530
+ },
531
+ });
532
+ /**
533
+ * Resolves a class's terminal base by walking up the extends-chain through
534
+ * classes declared in the same file. Returns the first imported/global base
535
+ * name, or the topmost in-file class's own name when the chain ends without a
536
+ * superclass (making an in-file hierarchy root its own common base).
537
+ */
538
+ function rootBaseOf(node, allClassDecls) {
539
+ let current = node;
540
+ const seen = new Set();
541
+ for (;;) {
542
+ const superName = getSuperClassName(current);
543
+ if (!superName) {
544
+ return current.id ? current.id.name : undefined;
545
+ }
546
+ const superDecl = allClassDecls.get(superName);
547
+ if (superDecl && !seen.has(superName)) {
548
+ seen.add(superName);
549
+ current = superDecl;
550
+ continue;
551
+ }
552
+ return superName;
553
+ }
554
+ }
555
+ /**
556
+ * Edge Case 6: a multi-class file is exempt when every exported class is a
557
+ * trivial constructor-only subclass AND they all share a common base (the same
558
+ * imported identifier, or a hierarchy rooted at one in-file class).
559
+ */
560
+ function isExemptErrorHierarchy(classNodes, allClassDecls) {
561
+ if (classNodes.length < 2)
562
+ return false;
563
+ if (!classNodes.every((node) => isConstructorOnlyClass(node))) {
564
+ return false;
565
+ }
566
+ const roots = classNodes.map((node) => rootBaseOf(node, allClassDecls));
567
+ if (roots.some((root) => root === undefined))
568
+ return false;
569
+ return roots.every((root) => root === roots[0]);
570
+ }
571
+ //# sourceMappingURL=enforce-single-exported-unit-per-file.js.map
@@ -0,0 +1 @@
1
+ export declare const noHarnessCoupledDisables: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"harnessCoupled", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;