@himynameisdave/oxlint-config 1.0.0
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/LICENSE +21 -0
- package/README.md +203 -0
- package/dist/base.d.ts +554 -0
- package/dist/base.js +1165 -0
- package/dist/index.d.ts +722 -0
- package/dist/index.js +23 -0
- package/dist/svelte.d.ts +27 -0
- package/dist/svelte.js +35 -0
- package/dist/type-aware.d.ts +88 -0
- package/dist/type-aware.js +189 -0
- package/dist/vitest.d.ts +95 -0
- package/dist/vitest.js +229 -0
- package/package.json +85 -0
package/dist/vitest.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { defineConfig } from 'oxlint';
|
|
2
|
+
/**
|
|
3
|
+
* Vitest add-on: every rule from oxlint's `vitest` plugin, decided explicitly.
|
|
4
|
+
* Opt in alongside base if your tests run under Vitest:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* export default defineConfig({ extends: [base, vitest] });
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* These rules only fire on test-shaped syntax (describe/it/test/expect), so
|
|
11
|
+
* they are inert in app code; no `files` scoping needed.
|
|
12
|
+
*
|
|
13
|
+
* Known limitation: oxlint resolves test functions by import source (`vitest`,
|
|
14
|
+
* `@jest/globals`) or bare globals. `import { it } from 'bun:test'` is NOT
|
|
15
|
+
* recognized, so none of these rules fire on bun:test-style suites. Bun users
|
|
16
|
+
* get no coverage from this add-on until oxlint supports bun:test upstream.
|
|
17
|
+
*/
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
plugins: ['vitest'],
|
|
20
|
+
rules: {
|
|
21
|
+
/* ================================================================== *
|
|
22
|
+
* vitest — correctness
|
|
23
|
+
* ================================================================== */
|
|
24
|
+
// A test with no assertion passes vacuously; it can never fail.
|
|
25
|
+
'vitest/expect-expect': 'error',
|
|
26
|
+
// vi.mock/vi.hoisted run before imports no matter where they're written;
|
|
27
|
+
// placing them lower misleads readers about execution order.
|
|
28
|
+
'vitest/hoisted-apis-on-top': 'error',
|
|
29
|
+
// An expect inside if/catch can silently never run; the test still passes.
|
|
30
|
+
'vitest/no-conditional-expect': 'error',
|
|
31
|
+
// Conditionally-registered tests mean different environments run different
|
|
32
|
+
// suites, so CI green stops meaning the same thing everywhere.
|
|
33
|
+
'vitest/no-conditional-tests': 'error',
|
|
34
|
+
// .skip rots invisibly and keeps CI green; use .todo for planned work
|
|
35
|
+
// (allowed, see warn-todo) or delete the test.
|
|
36
|
+
'vitest/no-disabled-tests': 'error',
|
|
37
|
+
// .only committed to a suite makes CI silently green while skipping every
|
|
38
|
+
// other test: the exact quiet failure this config exists to prevent.
|
|
39
|
+
'vitest/no-focused-tests': 'error',
|
|
40
|
+
// An expect in a describe body runs at collection time; its failure isn't
|
|
41
|
+
// attributed to any test.
|
|
42
|
+
'vitest/no-standalone-expect': 'error',
|
|
43
|
+
// Auto-numbered snapshots shift identity when assertions are added or
|
|
44
|
+
// reordered; a hint pins each one (fires only with multiple per test).
|
|
45
|
+
'vitest/prefer-snapshot-hint': 'error',
|
|
46
|
+
// An unawaited expect.poll()/expect.element() resolves after the test
|
|
47
|
+
// ends, so the assertion never gets a chance to fail.
|
|
48
|
+
'vitest/require-awaited-expect-poll': 'error',
|
|
49
|
+
// Under test.concurrent, the global expect's snapshot state races; the
|
|
50
|
+
// local context expect is the only reliable one.
|
|
51
|
+
'vitest/require-local-test-context-for-concurrent-snapshots': 'error',
|
|
52
|
+
// Untyped vi.fn() is (...args: any[]) => any, so wrong call shapes in
|
|
53
|
+
// assertions pass silently.
|
|
54
|
+
'vitest/require-mock-type-parameters': 'error',
|
|
55
|
+
// Bare toThrow() passes on ANY error; asserting the message pins which
|
|
56
|
+
// failure you actually meant.
|
|
57
|
+
'vitest/require-to-throw-message': 'error',
|
|
58
|
+
// A malformed describe callback (async, params, non-function) breaks
|
|
59
|
+
// collection quietly.
|
|
60
|
+
'vitest/valid-describe-callback': 'error',
|
|
61
|
+
// expect() with no matcher, or a matcher misuse, asserts nothing at all.
|
|
62
|
+
'vitest/valid-expect': 'error',
|
|
63
|
+
// A promise-chained expect must be awaited/returned or it asserts after
|
|
64
|
+
// the test has already passed.
|
|
65
|
+
'vitest/valid-expect-in-promise': 'error',
|
|
66
|
+
// Empty or dynamic-garbage titles break -t filtering and failure reports.
|
|
67
|
+
'vitest/valid-title': 'error',
|
|
68
|
+
// .todo is the sanctioned marker for planned tests; banning it would push
|
|
69
|
+
// people back to .skip, which no-disabled-tests rightly forbids.
|
|
70
|
+
'vitest/warn-todo': 'off',
|
|
71
|
+
/* ================================================================== *
|
|
72
|
+
* vitest — suspicious
|
|
73
|
+
* ================================================================== */
|
|
74
|
+
// Commented-out tests rot silently; delete them or mark .todo.
|
|
75
|
+
'vitest/no-commented-out-tests': 'error',
|
|
76
|
+
/* ================================================================== *
|
|
77
|
+
* vitest — pedantic
|
|
78
|
+
* ================================================================== */
|
|
79
|
+
// Branching in fixture setup (platform switches, parameterization) is
|
|
80
|
+
// legitimate; the real hazards are already errors via no-conditional-tests
|
|
81
|
+
// and no-conditional-expect.
|
|
82
|
+
'vitest/no-conditional-in-test': 'off',
|
|
83
|
+
/* ================================================================== *
|
|
84
|
+
* vitest — style
|
|
85
|
+
* ================================================================== */
|
|
86
|
+
// .each and .for differ semantically (.for passes the test context), so
|
|
87
|
+
// the choice is per-case, not a consistency to police.
|
|
88
|
+
'vitest/consistent-each-for': 'off',
|
|
89
|
+
// The base test-file override deliberately supports both .test and .spec
|
|
90
|
+
// conventions; picking one is repo policy, not lint.
|
|
91
|
+
'vitest/consistent-test-filename': 'off',
|
|
92
|
+
// One word per scope: the default (test at top level, it inside describe)
|
|
93
|
+
// matches how each reads grammatically.
|
|
94
|
+
'vitest/consistent-test-it': 'error',
|
|
95
|
+
// vi and vitest are the same object; one accessor (vi, the documented one)
|
|
96
|
+
// keeps greps and reviews single-spelling.
|
|
97
|
+
'vitest/consistent-vitest-vi': 'error',
|
|
98
|
+
// Assertion-count caps are arbitrary (same stance as max-lines).
|
|
99
|
+
'vitest/max-expects': 'off',
|
|
100
|
+
// Nesting-depth caps are arbitrary (same stance as max-lines).
|
|
101
|
+
'vitest/max-nested-describe': 'off',
|
|
102
|
+
// toBeCalled/toHaveBeenCalled are aliases; one canonical spelling.
|
|
103
|
+
'vitest/no-alias-methods': 'error',
|
|
104
|
+
// Two beforeEach in one describe both run; almost always a merge mistake.
|
|
105
|
+
'vitest/no-duplicate-hooks': 'error',
|
|
106
|
+
// Hooks are the normal setup mechanism; banning them outright is a niche
|
|
107
|
+
// philosophy this config doesn't share.
|
|
108
|
+
'vitest/no-hooks': 'off',
|
|
109
|
+
// Duplicate titles make failures ambiguous and -t filtering grab both.
|
|
110
|
+
'vitest/no-identical-title': 'error',
|
|
111
|
+
// import from node:test in a Vitest suite runs under a different runner's
|
|
112
|
+
// semantics; assertions quietly diverge.
|
|
113
|
+
'vitest/no-import-node-test': 'error',
|
|
114
|
+
// Twin of prefer-importing-vitest-globals; explicit imports win (below),
|
|
115
|
+
// so the globals-only counterpart stays off.
|
|
116
|
+
'vitest/no-importing-vitest-globals': 'off',
|
|
117
|
+
// Interpolated inline snapshots can't be updated by the runner (-u).
|
|
118
|
+
'vitest/no-interpolation-in-snapshots': 'error',
|
|
119
|
+
// Snapshot size caps are arbitrary (same stance as max-lines).
|
|
120
|
+
'vitest/no-large-snapshots': 'off',
|
|
121
|
+
// Importing from __mocks__ directly bypasses the mocking system the
|
|
122
|
+
// directory exists to feed.
|
|
123
|
+
'vitest/no-mocks-import': 'error',
|
|
124
|
+
// Inert without options; restricting matchers is a consumer decision.
|
|
125
|
+
'vitest/no-restricted-matchers': 'off',
|
|
126
|
+
// Inert without options; restricting vi methods is a consumer decision.
|
|
127
|
+
'vitest/no-restricted-vi-methods': 'off',
|
|
128
|
+
// xit/fdescribe are the sneaky spellings of .skip/.only; force the dotted
|
|
129
|
+
// forms so no-disabled-tests/no-focused-tests can see them.
|
|
130
|
+
'vitest/no-test-prefixes': 'error',
|
|
131
|
+
// A return in a test body usually hides an unawaited promise; await it.
|
|
132
|
+
'vitest/no-test-return-statement': 'error',
|
|
133
|
+
// expect(async () => { await f(); }) wraps a promise in a function for no
|
|
134
|
+
// reason; pass the promise straight to .rejects.
|
|
135
|
+
'vitest/no-unneeded-async-expect-function': 'error',
|
|
136
|
+
// Blank-line layout is oxfmt's job.
|
|
137
|
+
'vitest/padding-around-after-all-blocks': 'off',
|
|
138
|
+
// Blank-line layout is oxfmt's job.
|
|
139
|
+
'vitest/padding-around-test-blocks': 'off',
|
|
140
|
+
// One matcher stating the full contract (count + args) beats two that can
|
|
141
|
+
// drift apart.
|
|
142
|
+
'vitest/prefer-called-exactly-once-with': 'error',
|
|
143
|
+
// toHaveBeenCalledOnce reads as the assertion it is; twin of
|
|
144
|
+
// prefer-called-times, and exactly one direction can be on.
|
|
145
|
+
'vitest/prefer-called-once': 'error',
|
|
146
|
+
// Opposite twin of prefer-called-once (enabled above).
|
|
147
|
+
'vitest/prefer-called-times': 'off',
|
|
148
|
+
// Asserting the arguments catches wrong-payload bugs that a bare
|
|
149
|
+
// "was it called" never will.
|
|
150
|
+
'vitest/prefer-called-with': 'error',
|
|
151
|
+
// toBeGreaterThan(x) reports both values on failure; toBe(a > x) reports
|
|
152
|
+
// only true/false.
|
|
153
|
+
'vitest/prefer-comparison-matcher': 'error',
|
|
154
|
+
// describe(fn) survives renames; describe("fn") silently goes stale.
|
|
155
|
+
'vitest/prefer-describe-function-title': 'error',
|
|
156
|
+
// Hand-rolled for-loops around test() hide per-case titles that .each
|
|
157
|
+
// reports individually.
|
|
158
|
+
'vitest/prefer-each': 'error',
|
|
159
|
+
// expect(a === b).toBe(true) hides both operands in the failure output.
|
|
160
|
+
'vitest/prefer-equality-matcher': 'error',
|
|
161
|
+
// expect.assertions() in every test is ceremony; expect-expect and
|
|
162
|
+
// no-conditional-expect already cover the vacuous-pass risk.
|
|
163
|
+
'vitest/prefer-expect-assertions': 'off',
|
|
164
|
+
// await expect(p).resolves fails as an assertion; expect(await p) fails as
|
|
165
|
+
// an unhandled rejection with a worse trace.
|
|
166
|
+
'vitest/prefer-expect-resolves': 'error',
|
|
167
|
+
// toBeTypeOf("string") reports the actual value; expect(typeof x) reports
|
|
168
|
+
// two strings.
|
|
169
|
+
'vitest/prefer-expect-type-of': 'error',
|
|
170
|
+
// Lifecycle order (beforeAll, beforeEach, afterEach, afterAll) makes
|
|
171
|
+
// suite setup scannable.
|
|
172
|
+
'vitest/prefer-hooks-in-order': 'error',
|
|
173
|
+
// Hooks buried below tests are easy to miss when reading a suite.
|
|
174
|
+
'vitest/prefer-hooks-on-top': 'error',
|
|
175
|
+
// vi.mock(import("./m")) is typed and refactor-safe; the string form
|
|
176
|
+
// silently goes stale.
|
|
177
|
+
'vitest/prefer-import-in-mock': 'error',
|
|
178
|
+
// Explicit imports type-check and work whether or not globals: true is
|
|
179
|
+
// set; twin no-importing-vitest-globals stays off.
|
|
180
|
+
'vitest/prefer-importing-vitest-globals': 'error',
|
|
181
|
+
// Title casing is cosmetic.
|
|
182
|
+
'vitest/prefer-lowercase-title': 'off',
|
|
183
|
+
// mockResolvedValue(x) states intent; mockImplementation(() =>
|
|
184
|
+
// Promise.resolve(x)) buries it.
|
|
185
|
+
'vitest/prefer-mock-promise-shorthand': 'error',
|
|
186
|
+
// mockReturnValue(x) states intent; mockImplementation(() => x) buries it.
|
|
187
|
+
'vitest/prefer-mock-return-shorthand': 'error',
|
|
188
|
+
// vi.spyOn restores on mockRestore; assigning vi.fn() onto an object
|
|
189
|
+
// clobbers the method for every later test.
|
|
190
|
+
'vitest/prefer-spy-on': 'error',
|
|
191
|
+
// toBeTruthy passes on 1, "x", {}; toBe(true) asserts the actual boolean.
|
|
192
|
+
'vitest/prefer-strict-boolean-matchers': 'error',
|
|
193
|
+
// toStrictEqual catches undefined-vs-missing keys and class mismatches
|
|
194
|
+
// that toEqual ignores.
|
|
195
|
+
'vitest/prefer-strict-equal': 'error',
|
|
196
|
+
// toBe uses Object.is and prints a focused diff for primitives.
|
|
197
|
+
'vitest/prefer-to-be': 'error',
|
|
198
|
+
// Opposite of prefer-strict-boolean-matchers (enabled); loose truthiness
|
|
199
|
+
// is exactly what we ban.
|
|
200
|
+
'vitest/prefer-to-be-falsy': 'off',
|
|
201
|
+
// Targets jest-extended's toBeObject, which vanilla Vitest doesn't ship.
|
|
202
|
+
'vitest/prefer-to-be-object': 'off',
|
|
203
|
+
// Opposite of prefer-strict-boolean-matchers (enabled); loose truthiness
|
|
204
|
+
// is exactly what we ban.
|
|
205
|
+
'vitest/prefer-to-be-truthy': 'off',
|
|
206
|
+
// toContain prints the array on failure; .includes() toBe(true) prints a
|
|
207
|
+
// boolean.
|
|
208
|
+
'vitest/prefer-to-contain': 'error',
|
|
209
|
+
// toHaveBeenCalledTimes keeps the mock's call log in the failure output;
|
|
210
|
+
// asserting mock.calls.length loses it.
|
|
211
|
+
'vitest/prefer-to-have-been-called-times': 'error',
|
|
212
|
+
// toHaveLength reports the actual length; .length toBe(n) reports two
|
|
213
|
+
// bare numbers.
|
|
214
|
+
'vitest/prefer-to-have-length': 'error',
|
|
215
|
+
// An empty test() body silently passes forever; .todo marks the intent
|
|
216
|
+
// honestly (and warn-todo stays off to allow it).
|
|
217
|
+
'vitest/prefer-todo': 'error',
|
|
218
|
+
// Top-level fixture constants are idiomatic; hooks-only setup is ceremony.
|
|
219
|
+
'vitest/require-hook': 'off',
|
|
220
|
+
// Flat test files are fine; a mandatory describe wrapper is boilerplate.
|
|
221
|
+
'vitest/require-top-level-describe': 'off',
|
|
222
|
+
/* ================================================================== *
|
|
223
|
+
* vitest — restriction
|
|
224
|
+
* ================================================================== */
|
|
225
|
+
// The runner's default timeout already bounds every test; repeating it
|
|
226
|
+
// per-test is noise.
|
|
227
|
+
'vitest/require-test-timeout': 'off'
|
|
228
|
+
}
|
|
229
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@himynameisdave/oxlint-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "An opinionated oxlint config, by and for himynameisdave.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"config",
|
|
7
|
+
"himynameisdave",
|
|
8
|
+
"lint",
|
|
9
|
+
"linter",
|
|
10
|
+
"oxc",
|
|
11
|
+
"oxlint",
|
|
12
|
+
"oxlint-config"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/himynameisdave/oxlint-config",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/himynameisdave/oxlint-config/issues"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Dave Lunny <d@velunny.com>",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/himynameisdave/oxlint-config.git"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./base": {
|
|
36
|
+
"types": "./dist/base.d.ts",
|
|
37
|
+
"default": "./dist/base.js"
|
|
38
|
+
},
|
|
39
|
+
"./svelte": {
|
|
40
|
+
"types": "./dist/svelte.d.ts",
|
|
41
|
+
"default": "./dist/svelte.js"
|
|
42
|
+
},
|
|
43
|
+
"./type-aware": {
|
|
44
|
+
"types": "./dist/type-aware.d.ts",
|
|
45
|
+
"default": "./dist/type-aware.js"
|
|
46
|
+
},
|
|
47
|
+
"./vitest": {
|
|
48
|
+
"types": "./dist/vitest.d.ts",
|
|
49
|
+
"default": "./dist/vitest.js"
|
|
50
|
+
},
|
|
51
|
+
"./package.json": "./package.json"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc",
|
|
58
|
+
"lint": "tsc && oxlint -c oxlint.config.ts --deny-warnings",
|
|
59
|
+
"check-coverage": "tsc && bun scripts/check-coverage.ts",
|
|
60
|
+
"test:consumer": "tsc && bun scripts/consumer-smoke.ts",
|
|
61
|
+
"prepublishOnly": "npm run build",
|
|
62
|
+
"format": "oxfmt --write",
|
|
63
|
+
"format:check": "oxfmt --check",
|
|
64
|
+
"test": "bun run lint && bun run format:check && bun run check-coverage && bun run test:consumer",
|
|
65
|
+
"release": "np"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/bun": "^1.3.14",
|
|
69
|
+
"np": "^12.0.0",
|
|
70
|
+
"oxfmt": "0.61.0",
|
|
71
|
+
"oxlint": "1.76.0",
|
|
72
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
73
|
+
"typescript": "^7.0.0"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"oxlint": ">=1.76.0 <2",
|
|
77
|
+
"oxlint-tsgolint": ">=7.0.2001"
|
|
78
|
+
},
|
|
79
|
+
"peerDependenciesMeta": {
|
|
80
|
+
"oxlint-tsgolint": {
|
|
81
|
+
"optional": true
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"packageManager": "bun@1.3.13"
|
|
85
|
+
}
|