@noctcore/eslint-plugin-code-quality 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/README.md +58 -0
- package/dist/index.cjs +725 -0
- package/dist/index.d.cts +95 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.js +697 -0
- package/docs/rules/interface-prefix-i.md +44 -0
- package/docs/rules/no-bare-date-now.md +44 -0
- package/docs/rules/no-focused-tests.md +33 -0
- package/docs/rules/no-historical-comments.md +31 -0
- package/docs/rules/no-narration-comments.md +34 -0
- package/docs/rules/no-pr-reference-comments.md +36 -0
- package/docs/rules/no-process-exit.md +38 -0
- package/docs/rules/no-template-trim-empty-ternary.md +44 -0
- package/docs/rules/prefer-early-return.md +47 -0
- package/docs/rules/skipped-tests-need-tracking.md +50 -0
- package/package.json +64 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# `noctcore-code-quality/interface-prefix-i`
|
|
2
|
+
|
|
3
|
+
> Interface names must be `I` + an uppercase letter (`IUserProfile`). **Opinionated — not in `recommended`.**
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
An `I`-prefixed interface reads as an interface at a glance and never collides with a value of the same
|
|
8
|
+
name. This is a house-style naming convention, not a correctness rule — some teams find the prefix
|
|
9
|
+
noisy. It is therefore **excluded from the `recommended` preset**; enable it explicitly if your team
|
|
10
|
+
wants it.
|
|
11
|
+
|
|
12
|
+
## What it flags
|
|
13
|
+
|
|
14
|
+
A `TSInterfaceDeclaration` whose name is **not** `I` followed by an uppercase letter
|
|
15
|
+
(`/^I[A-Z]/`). `Input` fails (the letter after `I` is lowercase); `IUserProfile` passes.
|
|
16
|
+
|
|
17
|
+
Interfaces inside an ambient `declare module` / `declare global` block are **exempt** — their names are
|
|
18
|
+
dictated by the module being augmented (`Register`, `Window`).
|
|
19
|
+
|
|
20
|
+
Report-only: a rename touches every reference, which a single-file fixer cannot do safely.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// ✗ interface UserProfile { id: string; }
|
|
24
|
+
// ✗ interface Input { value: string; }
|
|
25
|
+
|
|
26
|
+
// ✓ interface IUserProfile { id: string; }
|
|
27
|
+
// ✓ declare global { interface Window { electron: unknown; } } // augmentation
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Options
|
|
31
|
+
|
|
32
|
+
None.
|
|
33
|
+
|
|
34
|
+
## Enabling it
|
|
35
|
+
|
|
36
|
+
Not part of `recommended`. Turn it on directly:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
'noctcore-code-quality/interface-prefix-i': 'error'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## When not to use it
|
|
43
|
+
|
|
44
|
+
If your codebase does not use the `I` interface-prefix convention (most don't) — leave it off.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# `noctcore-code-quality/no-bare-date-now`
|
|
2
|
+
|
|
3
|
+
> Read wall-clock time through a mockable `clock` util, not bare `Date.now()` / `new Date()`.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Business logic that reads `Date.now()` or `new Date()` directly is hard to test: every time-dependent
|
|
8
|
+
branch depends on the real clock. Routing wall-clock reads through a shared `clock` util
|
|
9
|
+
(`nowMs()` / `now()`) gives time-dependent code one seam you can freeze or advance in tests.
|
|
10
|
+
|
|
11
|
+
## What it flags
|
|
12
|
+
|
|
13
|
+
- `Date.now()` → suggests `nowMs()`.
|
|
14
|
+
- Zero-argument `new Date()` → suggests `now()`.
|
|
15
|
+
|
|
16
|
+
`new Date(value)` with an argument is a **parse** of an explicit instant, not a bare clock read, and
|
|
17
|
+
is never flagged. Files covered by `allowIn` are skipped entirely.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// ✗ bare clock reads in business logic
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
const created = new Date();
|
|
23
|
+
|
|
24
|
+
// ✓ through the clock seam
|
|
25
|
+
const start = nowMs();
|
|
26
|
+
const created = now();
|
|
27
|
+
|
|
28
|
+
// ✓ parsing an explicit instant
|
|
29
|
+
const at = new Date('2026-01-01T00:00:00Z');
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Options
|
|
33
|
+
|
|
34
|
+
| Option | Type | Default | Meaning |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| `allowIn` | `string[]` (globs) | `["**/clock.ts", "**/clock/**"]` | File-path globs (infra / the clock util itself) where bare `Date` is allowed. |
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
'noctcore-code-quality/no-bare-date-now': ['error', { allowIn: ['**/clock.ts', '**/*.timing.ts'] }]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## When not to use it
|
|
43
|
+
|
|
44
|
+
If your project has no clock abstraction and does not intend to add one.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# `noctcore-code-quality/no-focused-tests`
|
|
2
|
+
|
|
3
|
+
> Ban `.only` / `fdescribe` / `fit` so a focused test never silently lands in CI.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
A focused test (`it.only`, `fdescribe`, …) silences the rest of the suite. Committed by accident it
|
|
8
|
+
turns a green CI run into a lie — the suite "passes" because almost none of it ran. This rule makes a
|
|
9
|
+
focused test a lint error so it can't merge.
|
|
10
|
+
|
|
11
|
+
## What it flags
|
|
12
|
+
|
|
13
|
+
- `.only` resolved back to a `it` / `describe` / `test` runner, including chained modifiers
|
|
14
|
+
(`test.concurrent.only`, `describe.concurrent.only`).
|
|
15
|
+
- The Jest/Jasmine focused-call forms `fdescribe(...)`, `fit(...)`, `ddescribe(...)` — but only as a
|
|
16
|
+
bare-identifier callee, so an unrelated `obj.fit(...)` method is not flagged.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// ✗ it.only('runs', () => {});
|
|
20
|
+
// ✗ test.concurrent.only('case', () => {});
|
|
21
|
+
// ✗ fdescribe('suite', () => {});
|
|
22
|
+
|
|
23
|
+
// ✓ it('runs', () => {});
|
|
24
|
+
// ✓ layout.fit('contain'); // not a test runner
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Options
|
|
28
|
+
|
|
29
|
+
None.
|
|
30
|
+
|
|
31
|
+
## When not to use it
|
|
32
|
+
|
|
33
|
+
You almost always want this on. Disable only in throwaway scratch suites.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# `noctcore-code-quality/no-historical-comments`
|
|
2
|
+
|
|
3
|
+
> Comments describe the current invariant, not what the code used to do.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
A comment that frames code against its past — "before the fix", "we used to", "no longer" — rots the
|
|
8
|
+
moment the code changes again, and it forces the reader to reconstruct a history they don't need. The
|
|
9
|
+
history belongs in the commit message or PR description, where it is durable and out of the way.
|
|
10
|
+
This is also a common tell that a comment was generated to narrate a change rather than to explain the code.
|
|
11
|
+
|
|
12
|
+
## What it flags
|
|
13
|
+
|
|
14
|
+
Line and block comments (JSDoc `/** … */` blocks are exempt) matching narrow past-framing phrases:
|
|
15
|
+
`before/after the fix`, `before/after the refactor`, `we/this used to`, `used to be`, `no longer`,
|
|
16
|
+
`kept for backwards/legacy/compat`, `was/were a bug/footgun`, and `historical(ly)`.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// ✗ We used to read process.env directly here.
|
|
20
|
+
// ✗ Before the fix this collapsed to {}.
|
|
21
|
+
|
|
22
|
+
// ✓ Caps concurrent connections to avoid pool exhaustion.
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Options
|
|
26
|
+
|
|
27
|
+
None.
|
|
28
|
+
|
|
29
|
+
## When not to use it
|
|
30
|
+
|
|
31
|
+
If you deliberately keep inline change-history in comments.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# `noctcore-code-quality/no-narration-comments`
|
|
2
|
+
|
|
3
|
+
> Ban step-by-step "Now we… / First we…" narration comments.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Comments like "Here we attach the user" or "First, we parse the cookies" restate what the next line
|
|
8
|
+
of code already says. They add no information a reader can't get from the code and are a frequent tell
|
|
9
|
+
of a comment generated to narrate a change. Describe the **why** when a comment is warranted, or
|
|
10
|
+
delete it.
|
|
11
|
+
|
|
12
|
+
## What it flags
|
|
13
|
+
|
|
14
|
+
Line and block comments (JSDoc `/** … */` blocks are exempt) that **begin** with a narration
|
|
15
|
+
construction: `here we`, `now we`, `first[,] we`, `then[,] we`, `next[,] we`, `finally[,] we`,
|
|
16
|
+
`let's`, `let me`.
|
|
17
|
+
|
|
18
|
+
A bare leading word ("Next attempt…", "First run…") is fine — only the "we"/"let's" narration form matches.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// ✗ Now we attach the user to the socket.
|
|
22
|
+
// ✗ Let's validate the session token.
|
|
23
|
+
|
|
24
|
+
// ✓ WHY: Prisma reuses the pooled connection across requests.
|
|
25
|
+
// ✓ call next() to continue the middleware chain
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Options
|
|
29
|
+
|
|
30
|
+
None.
|
|
31
|
+
|
|
32
|
+
## When not to use it
|
|
33
|
+
|
|
34
|
+
If your team writes tutorial-style narrated code on purpose.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# `noctcore-code-quality/no-pr-reference-comments`
|
|
2
|
+
|
|
3
|
+
> PR/issue references belong in commit messages, not in source comments.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
`// fixes #123` or a link to a pull request rots the moment the repo moves, the issue tracker
|
|
8
|
+
migrates, or the numbering changes — and it drags the reader out of the code to chase context that a
|
|
9
|
+
`git blame` already carries. The git log and PR description are the canonical, durable home for
|
|
10
|
+
repo-history references.
|
|
11
|
+
|
|
12
|
+
## What it flags
|
|
13
|
+
|
|
14
|
+
Comments containing:
|
|
15
|
+
|
|
16
|
+
- a GitHub PR/issue URL (`https://github.com/owner/repo/pull/42`, `.../issues/42`);
|
|
17
|
+
- an action reference (`see`/`closes`/`fixes`/`resolves`/`refs` `#123`);
|
|
18
|
+
- a `PR #123` / `PR 123` reference;
|
|
19
|
+
- a bare `#123` at a word boundary.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// ✗ fixes #123
|
|
23
|
+
// ✗ See https://github.com/noctcore/eslint-plugins/pull/42 for context.
|
|
24
|
+
// ✗ workaround (#88)
|
|
25
|
+
|
|
26
|
+
// ✓ Trust-proxy depth for single-host Traefik.
|
|
27
|
+
const channel = "#general"; // ✓ not a comment
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Options
|
|
31
|
+
|
|
32
|
+
None.
|
|
33
|
+
|
|
34
|
+
## When not to use it
|
|
35
|
+
|
|
36
|
+
If your workflow relies on inline issue links in code.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# `noctcore-code-quality/no-process-exit`
|
|
2
|
+
|
|
3
|
+
> `process.exit()` belongs to bootstrap/shutdown and CLIs — not application code.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
`process.exit()` kills the whole process immediately, skipping pending I/O, `finally` blocks, and
|
|
8
|
+
graceful-shutdown handlers. In request-scoped, service, or renderer code that is a footgun: a single
|
|
9
|
+
call can take the entire process down mid-flight. Those layers should `throw` or reject and let the
|
|
10
|
+
lifecycle decide how to tear down. The legitimate exit sites are standalone scripts, CLI entrypoints,
|
|
11
|
+
and config files.
|
|
12
|
+
|
|
13
|
+
## What it flags
|
|
14
|
+
|
|
15
|
+
Any `process.exit(...)` call in a file **not** covered by `allowIn`. Both the dot form
|
|
16
|
+
(`process.exit()`) and the computed form (`process['exit']()`) are caught so a computed callee
|
|
17
|
+
cannot bypass the rule.
|
|
18
|
+
|
|
19
|
+
## Options
|
|
20
|
+
|
|
21
|
+
| Option | Type | Default | Meaning |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `allowIn` | `string[]` (globs) | see below | File-path globs where `process.exit()` is allowed. |
|
|
24
|
+
|
|
25
|
+
The globs are matched against the file path (a leading `**/` may match zero leading directories, so
|
|
26
|
+
the same pattern works for absolute and project-relative paths). Default:
|
|
27
|
+
|
|
28
|
+
```jsonc
|
|
29
|
+
["**/scripts/**", "**/bin/**", "**/cli/**", "**/*.config.{ts,js,mjs,cjs,cts,mts}"]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
'noctcore-code-quality/no-process-exit': ['error', { allowIn: ['**/scripts/**', '**/*.cli.ts'] }]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## When not to use it
|
|
37
|
+
|
|
38
|
+
Standalone CLI projects where every file is legitimately an entrypoint.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# `noctcore-code-quality/no-template-trim-empty-ternary`
|
|
2
|
+
|
|
3
|
+
> Extract the inline `` `…`.trim() === '' ? fallback : `…`.trim() `` pattern to a named util. **Niche — not in `recommended`.**
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
The inline shape `` `${a} ${b}`.trim() === '' ? fallback : `${a} ${b}`.trim() `` builds the same
|
|
8
|
+
template-plus-`trim()` expression **twice** and buries a small piece of display logic where it can't be
|
|
9
|
+
unit-tested on its own. Extracting it to a named helper (e.g. `buildDisplayName(...)`) builds the
|
|
10
|
+
expression once and gives it one testable home.
|
|
11
|
+
|
|
12
|
+
This is a very specific pattern, so the rule is **excluded from the `recommended` preset**. Enable it
|
|
13
|
+
explicitly if the shape recurs in your codebase.
|
|
14
|
+
|
|
15
|
+
## What it flags
|
|
16
|
+
|
|
17
|
+
A `ConditionalExpression` whose test is a `===` / `!==` comparison between an **empty-string literal**
|
|
18
|
+
and a **`.trim()` call on a template literal**, in either order.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// ✗
|
|
22
|
+
const name = `${first} ${last}`.trim() === '' ? email : `${first} ${last}`.trim();
|
|
23
|
+
const name = '' !== `${a}`.trim() ? `${a}`.trim() : fallback;
|
|
24
|
+
|
|
25
|
+
// ✓
|
|
26
|
+
const name = buildDisplayName({ first, last, fallback: email });
|
|
27
|
+
const trimmed = value.trim() === '' ? fallback : value; // not a template literal
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Options
|
|
31
|
+
|
|
32
|
+
None.
|
|
33
|
+
|
|
34
|
+
## Enabling it
|
|
35
|
+
|
|
36
|
+
Not part of `recommended`. Turn it on directly:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
'noctcore-code-quality/no-template-trim-empty-ternary': 'error'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## When not to use it
|
|
43
|
+
|
|
44
|
+
If this pattern doesn't appear in your codebase, there's nothing to gain from enabling it.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# `noctcore-code-quality/prefer-early-return`
|
|
2
|
+
|
|
3
|
+
> Prefer a guard clause over wrapping the whole function body in an `if`.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
When a function's entire body is wrapped in a single `if` with no `else`, the happy path is
|
|
8
|
+
needlessly indented and the reader has to hold the condition in their head to the end. Inverting
|
|
9
|
+
the condition into an early return keeps the meaningful work at the top level and reads top-to-bottom.
|
|
10
|
+
|
|
11
|
+
## What it flags
|
|
12
|
+
|
|
13
|
+
The **last** statement of a function block that is an `if` with:
|
|
14
|
+
|
|
15
|
+
- no `else` branch, and
|
|
16
|
+
- a block consequent holding **two or more** statements.
|
|
17
|
+
|
|
18
|
+
A single-statement `if`, an `if/else`, or an `if` that is not the final statement is left alone —
|
|
19
|
+
those are not body-wraps.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// ✗ the whole body is wrapped
|
|
23
|
+
function handle(x) {
|
|
24
|
+
if (x) {
|
|
25
|
+
doA();
|
|
26
|
+
doB();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ✓ guard clause
|
|
31
|
+
function handle(x) {
|
|
32
|
+
if (!x) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
doA();
|
|
36
|
+
doB();
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Options
|
|
41
|
+
|
|
42
|
+
None.
|
|
43
|
+
|
|
44
|
+
## When not to use it
|
|
45
|
+
|
|
46
|
+
If you prefer the wrapped style, or lint a codebase where trailing single-`if` bodies are idiomatic,
|
|
47
|
+
disable it.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `noctcore-code-quality/skipped-tests-need-tracking`
|
|
2
|
+
|
|
3
|
+
> A skipped test must carry a tracking marker (issue URL or `TODO(@owner)`) so the debt has an owner.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
`.skip` / `.fixme` / `xit` / `xdescribe` are escape hatches. Left unowned they rot into permanent dark
|
|
8
|
+
zones — nobody remembers why the test is off or who is meant to turn it back on. Requiring a tracking
|
|
9
|
+
marker (an issue URL or a `TODO(@owner)`) within a few lines of the skip keeps a human attached to the
|
|
10
|
+
debt.
|
|
11
|
+
|
|
12
|
+
`.only` is deliberately **not** covered here — [`no-focused-tests`](./no-focused-tests.md) bans it
|
|
13
|
+
outright, so it can never legitimately appear with or without tracking.
|
|
14
|
+
|
|
15
|
+
## What it flags
|
|
16
|
+
|
|
17
|
+
Any line matching a skip form — `it.skip(` / `test.skip(` / `describe.skip(`, the `.fixme(` variants,
|
|
18
|
+
`xit(`, `xdescribe(`, `xtest(` — with **no** tracking marker on that line or within the `lookback`
|
|
19
|
+
window above it.
|
|
20
|
+
|
|
21
|
+
Faithful to the original text-scanning implementation, the source is scanned line by line, so a marker
|
|
22
|
+
in a trailing comment, a preceding comment, or anywhere in the lookback window is honoured.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// ✓ tracked
|
|
26
|
+
// TODO(@alice): flaky under CI
|
|
27
|
+
it.skip('later', () => {});
|
|
28
|
+
|
|
29
|
+
it.skip('later', () => {}); // https://github.com/org/repo/issues/1
|
|
30
|
+
|
|
31
|
+
// ✗ untracked
|
|
32
|
+
it.skip('later', () => {});
|
|
33
|
+
xdescribe('later', () => {});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Options
|
|
37
|
+
|
|
38
|
+
| Option | Type | Default | Meaning |
|
|
39
|
+
| --- | --- | --- | --- |
|
|
40
|
+
| `markers` | `string[]` (regex sources) | `["https?://\\S+", "TODO\\(@?\\S+\\)"]` | Any pattern that, if found in the lookback window, satisfies the tracking requirement. Compiled with the `u` flag. |
|
|
41
|
+
| `lookback` | `integer` (≥0) | `30` | How many lines above the skip a marker may live and still count. |
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
// Require a Jira-style key instead of a URL / TODO.
|
|
45
|
+
'noctcore-code-quality/skipped-tests-need-tracking': ['error', { markers: ['[A-Z]+-\\d+'] }]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## When not to use it
|
|
49
|
+
|
|
50
|
+
If your project already enforces skip-tracking another way, or never skips tests.
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@noctcore/eslint-plugin-code-quality",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Portable code-quality, comment-hygiene, and test-discipline ESLint rules.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"docs",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"keywords": [
|
|
25
|
+
"eslint",
|
|
26
|
+
"eslintplugin",
|
|
27
|
+
"eslint-plugin",
|
|
28
|
+
"code-quality",
|
|
29
|
+
"noctcore"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"provenance": true
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/noctcore/eslint-plugins.git",
|
|
38
|
+
"directory": "packages/eslint-plugin-code-quality"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/noctcore/eslint-plugins/tree/main/packages/eslint-plugin-code-quality",
|
|
41
|
+
"bugs": "https://github.com/noctcore/eslint-plugins/issues",
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"test": "vitest run"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@noctcore/eslint-utils": "^0.1.0",
|
|
49
|
+
"@typescript-eslint/utils": "^8.61.1"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"eslint": ">=9.0.0",
|
|
53
|
+
"typescript": ">=5.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@noctcore/eslint-test-utils": "workspace:*",
|
|
57
|
+
"@types/node": "^22.0.0",
|
|
58
|
+
"@typescript-eslint/parser": "^8.61.1",
|
|
59
|
+
"@typescript-eslint/rule-tester": "^8.61.1",
|
|
60
|
+
"tsup": "^8.5.1",
|
|
61
|
+
"typescript": "^5.6.0",
|
|
62
|
+
"vitest": "^3"
|
|
63
|
+
}
|
|
64
|
+
}
|