@rdjperron/lint 0.1.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 +88 -0
- package/dist/anti-slop.d.mts +6 -0
- package/dist/anti-slop.mjs +1694 -0
- package/dist/anti-slop.mjs.map +1 -0
- package/dist/expo.d.mts +5 -0
- package/dist/expo.mjs +51 -0
- package/dist/expo.mjs.map +1 -0
- package/dist/i18n.d.mts +5 -0
- package/dist/i18n.mjs +50 -0
- package/dist/i18n.mjs.map +1 -0
- package/dist/react.d.mts +5 -0
- package/dist/react.mjs +73 -0
- package/dist/react.mjs.map +1 -0
- package/dist/rule-options-DrAXz8BD.mjs +18 -0
- package/dist/rule-options-DrAXz8BD.mjs.map +1 -0
- package/fixtures/README.md +63 -0
- package/fixtures/anti-slop/no-array-filter-map.fixture.ts +4 -0
- package/fixtures/anti-slop/no-chained-type-assertions.fixture.ts +7 -0
- package/fixtures/anti-slop/no-conditional-empty-object-spread.fixture.ts +4 -0
- package/fixtures/anti-slop/no-known-value-widening.fixture.ts +2 -0
- package/fixtures/anti-slop/no-module-mocking.fixture.ts +6 -0
- package/fixtures/anti-slop/no-object-parameters.fixture.ts +4 -0
- package/fixtures/anti-slop/no-reduce-accumulator-copy.fixture.ts +4 -0
- package/fixtures/anti-slop/no-reflect-apply.fixture.ts +6 -0
- package/fixtures/anti-slop/no-reflect-get.fixture.ts +4 -0
- package/fixtures/anti-slop/no-runtime-typeof.fixture.ts +4 -0
- package/fixtures/anti-slop/no-shape-in-symbol-names.fixture.ts +2 -0
- package/fixtures/anti-slop/no-unknown-parameters.fixture.ts +4 -0
- package/fixtures/anti-slop/no-unknown-returns.fixture.ts +4 -0
- package/fixtures/anti-slop/no-unknown-type-aliases.fixture.ts +2 -0
- package/fixtures/anti-slop/no-unsafe-dictionary-type.fixture.ts +2 -0
- package/fixtures/anti-slop/no-widen-then-assert.fixture.ts +9 -0
- package/fixtures/anti-slop/require-safety-comment-for-type-assertion.fixture.ts +5 -0
- package/fixtures/expo/static-public-env.fixture.ts +4 -0
- package/fixtures/i18n/no-hardcoded-jsx-text.fixture.tsx +4 -0
- package/fixtures/react/no-use-effect.fixture.tsx +9 -0
- package/package.json +50 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/shared/rule-options.ts
|
|
2
|
+
/**
|
|
3
|
+
* Rule options arrive as parsed JSON from the linter config, so this is the one
|
|
4
|
+
* place their shape is checked. Returns the first option when it is an object.
|
|
5
|
+
*/
|
|
6
|
+
function firstOptionObject(options) {
|
|
7
|
+
const first = options[0];
|
|
8
|
+
return typeof first === "object" && first !== null && !Array.isArray(first) ? first : {};
|
|
9
|
+
}
|
|
10
|
+
/** A string-valued key of the first option object, or undefined when absent or not a string. */
|
|
11
|
+
function stringOption(options, key) {
|
|
12
|
+
const value = firstOptionObject(options)[key];
|
|
13
|
+
return typeof value === "string" ? value : void 0;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { stringOption as t };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=rule-options-DrAXz8BD.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-options-DrAXz8BD.mjs","names":[],"sources":["../src/shared/rule-options.ts"],"sourcesContent":["import type { Options } from \"@oxlint/plugins\";\n\ntype OptionValue = Options[number];\n\n/**\n * Rule options arrive as parsed JSON from the linter config, so this is the one\n * place their shape is checked. Returns the first option when it is an object.\n */\nfunction firstOptionObject(options: Readonly<Options>): { readonly [key: string]: OptionValue } {\n const first = options[0];\n return typeof first === \"object\" && first !== null && !Array.isArray(first) ? first : {};\n}\n\n/** A string-valued key of the first option object, or undefined when absent or not a string. */\nexport function stringOption(options: Readonly<Options>, key: string): string | undefined {\n const value = firstOptionObject(options)[key];\n return typeof value === \"string\" ? value : undefined;\n}\n"],"mappings":";;;;;AAQA,SAAS,kBAAkB,SAAqE;CAC9F,MAAM,QAAQ,QAAQ;CACtB,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AACzF;;AAGA,SAAgB,aAAa,SAA4B,KAAiC;CACxF,MAAM,QAAQ,kBAAkB,OAAO,CAAC,CAAC;CACzC,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# fixtures: load-bearing test data, do not delete
|
|
2
|
+
|
|
3
|
+
One deliberately violating file per rule, in one directory per pack:
|
|
4
|
+
`anti-slop/<rule>.fixture.ts`, `react/no-use-effect.fixture.tsx`,
|
|
5
|
+
`i18n/no-hardcoded-jsx-text.fixture.tsx` and `expo/static-public-env.fixture.ts`. Each file trips
|
|
6
|
+
exactly the rule it is named after, and nothing else.
|
|
7
|
+
|
|
8
|
+
These ship in the published package (`files` in `package.json`), so a consumer proves the rules
|
|
9
|
+
fire through its own linter, not ours.
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
The linter lives inside the consumer's toolchain (under Vite+, inside the `vp` binary) and moves
|
|
14
|
+
independently of any lockfile. The rules run through oxlint's JS-plugin bridge. A rule can stop
|
|
15
|
+
firing with no diff anywhere: after a linter upgrade, after a plugin API skew, after an ignore
|
|
16
|
+
pattern swallows the wrong path.
|
|
17
|
+
|
|
18
|
+
And a dead lint rule is silent. "Rule reports nothing" looks identical to "code has no
|
|
19
|
+
violations". Nothing else would notice.
|
|
20
|
+
|
|
21
|
+
The source repo's `scripts/verify-lint-fixtures.mjs` (in CI and in `vp run ready`) lints each
|
|
22
|
+
pack's fixtures and asserts a positive: every rule must fire, each on its own fixture. If a rule
|
|
23
|
+
goes dead, the run fails loudly instead of going quietly green.
|
|
24
|
+
|
|
25
|
+
## How it relates to the unit tests
|
|
26
|
+
|
|
27
|
+
Two layers, different questions:
|
|
28
|
+
|
|
29
|
+
| Layer | Question it answers | Where |
|
|
30
|
+
| -------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
31
|
+
| This directory + a verify script | Does each rule fire through the real pipeline: the bundled oxlint, the `jsPlugins` wiring, the actual config? | `fixtures/`, the consumer's `scripts/verify-lint-fixtures.mjs` |
|
|
32
|
+
| Unit tests (RuleTester) | Is each rule's logic right? Valid cases stay quiet, invalid cases report, with per-case precision. | `tests/` in the source repo (not published) |
|
|
33
|
+
|
|
34
|
+
The unit tests catch a locally edited rule that starts over- or under-firing. This layer catches
|
|
35
|
+
the rule not running at all. Both are needed.
|
|
36
|
+
|
|
37
|
+
## Rules of the house
|
|
38
|
+
|
|
39
|
+
- Do not delete or "clean up" these files. They are the regression proof for rules nobody
|
|
40
|
+
upstream maintains for us.
|
|
41
|
+
- In the source repo they are in `lint.ignorePatterns` and `fmt.ignorePatterns`, so a plain
|
|
42
|
+
`vp check` stays quiet. The verify script reaches them through a transient symlink at
|
|
43
|
+
`scripts/.lint-fixtures/<pack>`, because no `vp lint` flag re-includes a config-ignored path and
|
|
44
|
+
oxlint skips `node_modules` by default.
|
|
45
|
+
- Never gitignore that view. oxlint honours `.gitignore`, so gitignoring anything on the
|
|
46
|
+
verification path silently disables the whole check (this happened once; the script now detects
|
|
47
|
+
it with `git check-ignore` and says so).
|
|
48
|
+
- Name fixtures `*.fixture.ts` / `*.fixture.tsx`, never `*.test.ts`, or Vitest collects them and
|
|
49
|
+
the deliberately broken code fails the test run.
|
|
50
|
+
- One rule per file. A fixture that trips two rules makes the per-rule assertion ambiguous.
|
|
51
|
+
- Expected advisory noise in the source repo: the type-aware pass also reports `typescript(TS…)`
|
|
52
|
+
on the view, because no tsconfig covers `scripts/.lint-fixtures/` (no React types, no `process`
|
|
53
|
+
types, no `jsx` setting). The script lists those as non-pack diagnostics rather than hiding
|
|
54
|
+
them; only a pack rule that did not fire fails the run.
|
|
55
|
+
|
|
56
|
+
## When a rule stops firing after a `vp` upgrade
|
|
57
|
+
|
|
58
|
+
1. `vp toolchain oxlint`: did the bundled oxlint move?
|
|
59
|
+
2. `vp why @oxlint/plugins`: if `vite-plus` now declares a different version, move the exact
|
|
60
|
+
pin to it and reinstall. In the source repo the parity test in `tests/` fails until you do.
|
|
61
|
+
3. Re-run the verify script.
|
|
62
|
+
4. Still dead? The rule's AST expectations may have changed under the new oxc version. Read the
|
|
63
|
+
rule in `src/<pack>/rules/`, fix it, add the case to `tests/rules/<pack>/`, and release.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Fixture for anti-slop/no-module-mocking.
|
|
2
|
+
// `vi` is deliberately left undeclared: the rule's global/unresolved-reference
|
|
3
|
+
// path is what recognises `vi.mock` without importing from "vitest" (which
|
|
4
|
+
// `vite-plus/prefer-vite-plus-imports` forbids in this repo).
|
|
5
|
+
// @ts-expect-error -- `vi` is intentionally not declared in this fixture.
|
|
6
|
+
vi.mock("./clock.ts");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Fixture for anti-slop/no-widen-then-assert.
|
|
2
|
+
function project(entry: { id: string }): string {
|
|
3
|
+
const widened: unknown = entry;
|
|
4
|
+
// SAFETY: fixture file; the widen-then-assert flow is the behaviour under test.
|
|
5
|
+
const narrowed = widened as { id: string };
|
|
6
|
+
return narrowed.id;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const projected = project({ id: "a" });
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rdjperron/lint",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Oxlint JS plugins: the anti-slop, react-policy, i18n and expo rule packs, shipped with the fixture that proves each rule fires.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"fixtures",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
"./anti-slop": {
|
|
14
|
+
"types": "./dist/anti-slop.d.mts",
|
|
15
|
+
"default": "./dist/anti-slop.mjs"
|
|
16
|
+
},
|
|
17
|
+
"./react": {
|
|
18
|
+
"types": "./dist/react.d.mts",
|
|
19
|
+
"default": "./dist/react.mjs"
|
|
20
|
+
},
|
|
21
|
+
"./i18n": {
|
|
22
|
+
"types": "./dist/i18n.d.mts",
|
|
23
|
+
"default": "./dist/i18n.mjs"
|
|
24
|
+
},
|
|
25
|
+
"./expo": {
|
|
26
|
+
"types": "./dist/expo.d.mts",
|
|
27
|
+
"default": "./dist/expo.mjs"
|
|
28
|
+
},
|
|
29
|
+
"./fixtures/*": "./fixtures/*",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@oxlint/plugins": "1.79.0",
|
|
34
|
+
"@types/node": "^24",
|
|
35
|
+
"typescript": "^7.0.2",
|
|
36
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.1",
|
|
37
|
+
"vite-plus": "0.3.1"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@oxlint/plugins": "^1.79.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=24"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "vp pack",
|
|
47
|
+
"test": "vp test",
|
|
48
|
+
"check": "vp check"
|
|
49
|
+
}
|
|
50
|
+
}
|