-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheslint.config.mjs
More file actions
138 lines (121 loc) · 5.05 KB
/
Copy patheslint.config.mjs
File metadata and controls
138 lines (121 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import prettier from 'eslint-config-prettier';
/**
* Lint rules for iobroker-sync.
*
* The type-checked ruleset is used deliberately: this tool is full of async I/O
* against a live home-automation system, and the rules that actually matter here
* (floating promises, misused promises) cannot be detected without type information.
*
* Formatting is Prettier's job — `eslint-config-prettier` last switches off every
* stylistic rule so the two never argue.
*/
export default tseslint.config(
{
ignores: ['dist/', 'dist-test/', 'node_modules/', 'coverage/', 'eslint.config.mjs'],
},
js.configs.recommended,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
// Both configs: src/ is covered by tsconfig.json, test/ only by
// tsconfig.test.json, and type-aware rules need every file in a project.
project: ['./tsconfig.json', './tsconfig.test.json'],
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// --- Correctness that matters for this project -----------------------
// An unawaited write to a live instance is the whole nightmare scenario:
// the command reports success and exits while the request is in flight.
// node:test's describe/it return promises the runner owns; telling the rule
// about them keeps it strict everywhere else instead of switching it off.
'@typescript-eslint/no-floating-promises': [
'error',
{
allowForKnownSafeCalls: [
{
from: 'package',
package: 'node:test',
name: ['describe', 'it', 'test', 'before', 'after', 'beforeEach', 'afterEach'],
},
],
},
],
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/return-await': ['error', 'in-try-catch'],
// --- Deliberate relaxations ------------------------------------------
// ioBroker objects are genuinely dynamic; `unknown` is narrowed at the
// boundaries in types.ts rather than pretended away everywhere.
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
// Off on purpose. Almost every report is a guard on data that arrived over
// a websocket — `socket.emit<T>()` returns `T`, but that type is a claim
// about what the server *should* send, not a guarantee. The rule sees the
// declared type and calls `result?.rows ?? []` unnecessary; at runtime a
// malformed reply makes it essential. Following the rule here would trade
// a handled edge case for a crash against a live instance.
'@typescript-eslint/no-unnecessary-condition': 'off',
// `return doSomething()` where the callee returns void reads fine and is
// used consistently in the command layer.
'@typescript-eslint/no-confusing-void-expression': 'off',
// ioBroker represents "unset" as an empty string as often as undefined, so
// `engineType || '?'` is deliberate: `??` would keep the empty string and
// silently render a blank column. Strings are exempted rather than the whole
// rule, so `??` is still enforced where the distinction cannot bite.
'@typescript-eslint/prefer-nullish-coalescing': [
'error',
{ ignorePrimitives: { string: true } },
],
// Both uses are `delete record[dynamicKey]` on a Record<string, T> — a
// credential entry and a manifest entry. That is what the operator is for;
// the rule targets deleting fixed keys off a shaped object.
'@typescript-eslint/no-dynamic-delete': 'off',
// Template literals interpolate ids, paths and counts; stringifying a
// number is not a bug worth failing a build over.
'@typescript-eslint/restrict-template-expressions': [
'error',
{ allowNumber: true, allowBoolean: true },
],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
},
},
// Commands must route user-facing output through ctx.log, never console.*.
// Encoding the rule here means it is enforced rather than remembered.
{
files: ['src/**/*.ts'],
ignores: ['src/cli.ts'],
rules: {
'no-console': 'error',
},
},
// cli.ts is the one place that owns stdout/stderr.
{
files: ['src/cli.ts'],
rules: {
'no-console': 'off',
},
},
// Tests assert on shapes the type system cannot see, and reach into internals
// on purpose.
{
files: ['test/**/*.ts'],
rules: {
'no-console': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
},
},
prettier,
);