ai-deslop 0.2.1 → 0.2.2
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 +34 -108
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/rules/no-duplicate-types.d.ts +2 -0
- package/dist/rules/no-duplicate-types.js +143 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -13,117 +13,43 @@ npm install --save-dev ai-deslop
|
|
|
13
13
|
|
|
14
14
|
Ships compiled JavaScript — works with any oxlint JS-plugin runtime (Bun, Deno, or Node.js).
|
|
15
15
|
|
|
16
|
-
## Usage
|
|
17
|
-
|
|
18
|
-
Register the plugin in `oxlint.config.ts` and enable every rule as an error via the exported `recommended` config:
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
import { defineConfig } from "oxlint";
|
|
22
|
-
import { configs as deslopConfigs } from "ai-deslop";
|
|
23
|
-
|
|
24
|
-
export default defineConfig({
|
|
25
|
-
jsPlugins: ["ai-deslop"],
|
|
26
|
-
options: {
|
|
27
|
-
...deslopConfigs.recommended.options,
|
|
28
|
-
},
|
|
29
|
-
rules: {
|
|
30
|
-
...deslopConfigs.recommended.rules,
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
The `recommended` config also enables standard type-aware rules (`typescript/no-deprecated`, `typescript/no-floating-promises`), so it sets `options.typeAware`. Type-aware linting requires the `oxlint-tsgolint` package to be installed.
|
|
36
|
-
|
|
37
|
-
Or with `.oxlintrc.json` (list the rules explicitly):
|
|
38
|
-
|
|
39
|
-
```json
|
|
40
|
-
{
|
|
41
|
-
"jsPlugins": ["ai-deslop"],
|
|
42
|
-
"options": {
|
|
43
|
-
"typeAware": true
|
|
44
|
-
},
|
|
45
|
-
"rules": {
|
|
46
|
-
"deslop/no-array-filter-map": "error",
|
|
47
|
-
"deslop/no-reduce-accumulator-copy": "error",
|
|
48
|
-
"deslop/no-chained-type-assertions": "error",
|
|
49
|
-
"deslop/no-conditional-empty-object-spread": "error",
|
|
50
|
-
"deslop/no-known-value-widening": "error",
|
|
51
|
-
"deslop/no-module-mocking": "error",
|
|
52
|
-
"deslop/no-object-parameters": "error",
|
|
53
|
-
"deslop/no-reflect-apply": "error",
|
|
54
|
-
"deslop/no-reflect-get": "error",
|
|
55
|
-
"deslop/no-runtime-typeof": "error",
|
|
56
|
-
"deslop/no-shape-in-symbol-names": "error",
|
|
57
|
-
"deslop/no-unknown-parameters": "error",
|
|
58
|
-
"deslop/no-unknown-returns": "error",
|
|
59
|
-
"deslop/no-unknown-type-aliases": "error",
|
|
60
|
-
"deslop/no-unsafe-dictionary-type": "error",
|
|
61
|
-
"deslop/no-widen-then-assert": "error",
|
|
62
|
-
"deslop/require-safety-comment-for-type-assertion": "error",
|
|
63
|
-
"deslop/no-call-only-assertions": "error",
|
|
64
|
-
"deslop/no-pass-through-type-alias": "error",
|
|
65
|
-
"typescript/no-deprecated": "error",
|
|
66
|
-
"typescript/no-floating-promises": "error"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
16
|
## Rules
|
|
72
17
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
|
18
|
+
| Rule | Status | Description |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| [`no-array-filter-map`](docs/deslop.md) | Recommended | Rejects adjacent eager array filter/map passes; allows lazy iterator pipelines. |
|
|
21
|
+
| [`no-reduce-accumulator-copy`](docs/deslop.md) | Recommended | Rejects non-spread accumulator copies inside reducers. Enable native `oxc/no-accumulating-spread` alongside it. |
|
|
22
|
+
| [`no-chained-type-assertions`](docs/deslop.md) | Recommended | Rejects nested `as` / angle-bracket assertions that fabricate evidence. |
|
|
23
|
+
| [`no-conditional-empty-object-spread`](docs/deslop.md) | Recommended | Reports object spreads using a conditional `{}` branch to omit fields. |
|
|
24
|
+
| [`no-known-value-widening`](docs/deslop.md) | Recommended | Rejects known expressions flowing into explicit `unknown`, `object`, or open dictionaries. |
|
|
25
|
+
| [`no-module-mocking`](docs/deslop.md) | Recommended | Rejects Vitest and Jest module mocks. |
|
|
26
|
+
| [`no-object-parameters`](docs/deslop.md) | Recommended | Rejects `object` on function inputs. |
|
|
27
|
+
| [`no-reflect-apply`](docs/deslop.md) | Recommended | Rejects global `Reflect.apply`. |
|
|
28
|
+
| [`no-reflect-get`](docs/deslop.md) | Recommended | Rejects global `Reflect.get`. |
|
|
29
|
+
| [`no-runtime-typeof`](docs/deslop.md) | Recommended | Requires boundary parsing instead of ad hoc `typeof` narrowing. |
|
|
30
|
+
| [`no-shape-in-symbol-names`](docs/deslop.md) | Recommended | Rejects `shape` in locally owned symbol names. |
|
|
31
|
+
| [`no-unknown-parameters`](docs/deslop.md) | Recommended | Rejects `unknown` on function inputs. |
|
|
32
|
+
| [`no-unknown-returns`](docs/deslop.md) | Recommended | Rejects return contracts resolving to `unknown`. |
|
|
33
|
+
| [`no-unknown-type-aliases`](docs/deslop.md) | Recommended | Rejects aliases whose resolved type is `unknown`. |
|
|
34
|
+
| [`no-unsafe-dictionary-type`](docs/deslop.md) | Recommended | Rejects dictionary values based on unsafe escape hatches. |
|
|
35
|
+
| [`no-widen-then-assert`](docs/deslop.md) | Recommended | Rejects widening known evidence before narrowing assertions. |
|
|
36
|
+
| [`require-safety-comment-for-type-assertion`](docs/deslop.md) | Recommended | Requires an invariant justification for non-const assertions. |
|
|
37
|
+
| [`no-call-only-assertions`](docs/deslop.md) | Recommended | Flags tests whose assertions only check mock calls. |
|
|
38
|
+
| [`no-pass-through-type-alias`](docs/deslop.md) | Recommended | Disallows aliases that only rename another type. |
|
|
39
|
+
| [`no-duplicate-types`](docs/deslop.md#no-duplicate-types) | Opt-in | Reports exact duplicate object contracts. No fixer. |
|
|
40
|
+
| [`canonical-class-names`](docs/tailwind.md) | Opt-in | Fixes non-canonical Tailwind CSS v4 class spellings. |
|
|
41
|
+
|
|
42
|
+
| Standard rule | Status | Description |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| `typescript/no-deprecated` | Recommended | Disallows using code marked `@deprecated`. Requires type-aware linting. |
|
|
45
|
+
| `typescript/no-floating-promises` | Recommended | Disallows floating promises. Requires type-aware linting. |
|
|
46
|
+
|
|
47
|
+
## Guides
|
|
48
|
+
|
|
49
|
+
| Guide | Contents |
|
|
76
50
|
| --- | --- |
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
| `no-chained-type-assertions` | Rejects nested `as` / angle-bracket assertions that fabricate evidence (`as const` chains stay valid). |
|
|
80
|
-
| `no-conditional-empty-object-spread` | Reports object spreads using a conditional `{}` branch to omit fields. |
|
|
81
|
-
| `no-known-value-widening` | Rejects known expressions flowing into explicit `unknown` / `object` / open-dictionary targets. |
|
|
82
|
-
| `no-module-mocking` | Rejects Vitest and Jest `mock` / `doMock` / `unstable_mockModule` calls. |
|
|
83
|
-
| `no-object-parameters` | Rejects `object` (and aliases resolving to it) on function inputs. |
|
|
84
|
-
| `no-reflect-apply` | Rejects global `Reflect.apply` in favor of typed function calls. |
|
|
85
|
-
| `no-reflect-get` | Rejects global `Reflect.get` in favor of typed property access or boundary parsing. |
|
|
86
|
-
| `no-runtime-typeof` | Requires boundary parsing instead of ad hoc `typeof` narrowing (`typeof x === "undefined"` probes stay allowed). |
|
|
87
|
-
| `no-shape-in-symbol-names` | Rejects the case-insensitive substring `shape` in locally owned symbol names. |
|
|
88
|
-
| `no-unknown-parameters` | Rejects `unknown` on function inputs (except the `cause` convention and type-predicate subjects). |
|
|
89
|
-
| `no-unknown-returns` | Rejects function contracts resolving to `unknown` / `Promise<unknown>`. |
|
|
90
|
-
| `no-unknown-type-aliases` | Rejects aliases whose resolved type is `unknown`. |
|
|
91
|
-
| `no-unsafe-dictionary-type` | Rejects dictionary value contracts based on `unknown`, `any`, `object`, `{}`. |
|
|
92
|
-
| `no-widen-then-assert` | Rejects flows that widen known evidence then assert it back to a narrower type. |
|
|
93
|
-
| `require-safety-comment-for-type-assertion` | Requires a nearby invariant justification comment (default marker `SAFETY:`) for each non-const assertion. |
|
|
94
|
-
| `no-call-only-assertions` | Flags tests whose every assertion only checks a mock was called (`toHaveBeenCalledWith` stays allowed). |
|
|
95
|
-
| `no-pass-through-type-alias` | Disallows type aliases that only rename another type. |
|
|
96
|
-
|
|
97
|
-
The rules use Oxlint's ESTree and lexical-scope APIs rather than a TypeScript type checker. They resolve same-file aliases but do not infer imported type definitions or cross-file call signatures.
|
|
98
|
-
|
|
99
|
-
### Standard (`typescript/*`, in `recommended`)
|
|
100
|
-
|
|
101
|
-
| Rule | Description |
|
|
102
|
-
| --- | --- |
|
|
103
|
-
| `typescript/no-deprecated` | Disallows using code marked `@deprecated`. Requires type-aware linting. |
|
|
104
|
-
| `typescript/no-floating-promises` | Disallows floating Promises without handling. Requires type-aware linting. |
|
|
105
|
-
|
|
106
|
-
### Opt-in (`deslop/canonical-class-names`, default off)
|
|
107
|
-
|
|
108
|
-
Enforces canonical Tailwind CSS class spellings with `--fix` support (`mt-[16px]` → `mt-4`). Same source of truth as the Tailwind language server. Excluded from `recommended` because it requires a `cssPath` option — add it manually:
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
import { defineConfig } from "oxlint";
|
|
112
|
-
import { configs as deslopConfigs } from "ai-deslop";
|
|
113
|
-
|
|
114
|
-
export default defineConfig({
|
|
115
|
-
jsPlugins: ["ai-deslop"],
|
|
116
|
-
options: {
|
|
117
|
-
...deslopConfigs.recommended.options,
|
|
118
|
-
},
|
|
119
|
-
rules: {
|
|
120
|
-
...deslopConfigs.recommended.rules,
|
|
121
|
-
"deslop/canonical-class-names": ["warn", { cssPath: "./src/styles.css" }],
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Requires Tailwind CSS v4 (`tailwindcss` is an optional peer). Options: `cssPath` (required, absolute or relative to cwd), `rootFontSize` (default `16`), `attributes` (default `["class", "className"]`), `calleeFunctions` (default `["cn", "clsx", "cva", "twMerge", "tw", "classNames", "cx"]`). Only rewrites individual spellings — ordering/dedup belongs to the formatter. Strings with `${}` interpolations are skipped.
|
|
51
|
+
| [Deslop rules](docs/deslop.md) | Recommended and opt-in deslop configuration, complete TypeScript/JSON examples, and `no-duplicate-types` options. |
|
|
52
|
+
| [Tailwind canonical class names](docs/tailwind.md) | Tailwind v4 setup, complete TypeScript/JSON examples, and every supported option. |
|
|
127
53
|
|
|
128
54
|
## Credits
|
|
129
55
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
2
2
|
/** Every `deslop/*` rule, plus selected standard rules, each set to `"error"`. Spread into the `rules` field of an oxlint config. */
|
|
3
3
|
export declare const recommendedRules: Record<string, "error">;
|
|
4
|
-
/** ESLint flat-config style configs. `recommended` enables every `deslop/*` rule as `"error"` (
|
|
4
|
+
/** ESLint flat-config style configs. `recommended` enables every recommended `deslop/*` rule as `"error"` (excluding opt-in rules), plus standard `typescript/*` rules. The `typescript/*` rules require type-aware linting (`options.typeAware`), so `recommended` sets it. */
|
|
5
5
|
export declare const configs: {
|
|
6
6
|
recommended: {
|
|
7
7
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ import { noWidenThenAssertRule } from "./rules/no-widen-then-assert.js";
|
|
|
18
18
|
import { requireSafetyCommentForTypeAssertionRule } from "./rules/require-safety-comment-for-type-assertion.js";
|
|
19
19
|
import { noCallOnlyAssertionsRule } from "./rules/no-call-only-assertions.js";
|
|
20
20
|
import { noPassThroughTypeAliasRule } from "./rules/no-pass-through-type-alias.js";
|
|
21
|
+
import { noDuplicateTypesRule } from "./rules/no-duplicate-types.js";
|
|
21
22
|
import { canonicalClassNames } from "./tailwind/rule.js";
|
|
22
23
|
/** Every `deslop/*` rule, plus selected standard rules, each set to `"error"`. Spread into the `rules` field of an oxlint config. */
|
|
23
24
|
export const recommendedRules = {
|
|
@@ -43,7 +44,7 @@ export const recommendedRules = {
|
|
|
43
44
|
"typescript/no-deprecated": "error",
|
|
44
45
|
"typescript/no-floating-promises": "error",
|
|
45
46
|
};
|
|
46
|
-
/** ESLint flat-config style configs. `recommended` enables every `deslop/*` rule as `"error"` (
|
|
47
|
+
/** ESLint flat-config style configs. `recommended` enables every recommended `deslop/*` rule as `"error"` (excluding opt-in rules), plus standard `typescript/*` rules. The `typescript/*` rules require type-aware linting (`options.typeAware`), so `recommended` sets it. */
|
|
47
48
|
export const configs = {
|
|
48
49
|
recommended: {
|
|
49
50
|
name: "deslop/recommended",
|
|
@@ -74,6 +75,7 @@ const deslopPlugin = eslintCompatPlugin({
|
|
|
74
75
|
"require-safety-comment-for-type-assertion": requireSafetyCommentForTypeAssertionRule,
|
|
75
76
|
"no-call-only-assertions": noCallOnlyAssertionsRule,
|
|
76
77
|
"no-pass-through-type-alias": noPassThroughTypeAliasRule,
|
|
78
|
+
"no-duplicate-types": noDuplicateTypesRule,
|
|
77
79
|
// Opt-in: NOT in `recommendedRules`. Requires a `cssPath` option, so users add it manually.
|
|
78
80
|
"canonical-class-names": canonicalClassNames,
|
|
79
81
|
},
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { defineRule } from "@oxlint/plugins";
|
|
2
|
+
function propertyKey(node) {
|
|
3
|
+
const value = node;
|
|
4
|
+
if (value.type === "Identifier" && typeof value.name === "string")
|
|
5
|
+
return value.name;
|
|
6
|
+
if (typeof value.value === "string")
|
|
7
|
+
return JSON.stringify(value.value);
|
|
8
|
+
if (typeof value.value === "number")
|
|
9
|
+
return String(value.value);
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
function literalValue(node) {
|
|
13
|
+
const literal = node.literal;
|
|
14
|
+
if (typeof literal.value === "string")
|
|
15
|
+
return JSON.stringify(literal.value);
|
|
16
|
+
if (typeof literal.value === "number" || typeof literal.value === "boolean")
|
|
17
|
+
return String(literal.value);
|
|
18
|
+
if (typeof literal.value === "bigint")
|
|
19
|
+
return `${literal.value}n`;
|
|
20
|
+
if (literal.type === "UnaryExpression" && literal.operator === "-") {
|
|
21
|
+
if (typeof literal.argument?.value === "number")
|
|
22
|
+
return `-${literal.argument.value}`;
|
|
23
|
+
if (typeof literal.argument?.value === "bigint")
|
|
24
|
+
return `-${literal.argument.value}n`;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function canonicalTypeName(node) {
|
|
29
|
+
if (node.type === "Identifier")
|
|
30
|
+
return node.name;
|
|
31
|
+
if (node.type !== "TSQualifiedName")
|
|
32
|
+
return null;
|
|
33
|
+
const left = canonicalTypeName(node.left);
|
|
34
|
+
return left === null ? null : `${left}.${node.right.name}`;
|
|
35
|
+
}
|
|
36
|
+
function canonicalMembers(members, parameters) {
|
|
37
|
+
const result = [];
|
|
38
|
+
for (const member of members) {
|
|
39
|
+
if (member.type !== "TSPropertySignature" || member.computed || member.typeAnnotation === null)
|
|
40
|
+
return null;
|
|
41
|
+
const key = propertyKey(member.key);
|
|
42
|
+
const type = canonicalType(member.typeAnnotation.typeAnnotation, parameters);
|
|
43
|
+
if (key === null || type === null)
|
|
44
|
+
return null;
|
|
45
|
+
result.push(`prop(${key},${member.optional ? "?" : "!"},${member.readonly ? "ro" : "rw"},${type})`);
|
|
46
|
+
}
|
|
47
|
+
result.sort();
|
|
48
|
+
return `{${result.join(",")}}`;
|
|
49
|
+
}
|
|
50
|
+
function canonicalType(node, parameters) {
|
|
51
|
+
switch (node.type) {
|
|
52
|
+
case "TSAnyKeyword":
|
|
53
|
+
case "TSBigIntKeyword":
|
|
54
|
+
case "TSBooleanKeyword":
|
|
55
|
+
case "TSNeverKeyword":
|
|
56
|
+
case "TSNullKeyword":
|
|
57
|
+
case "TSNumberKeyword":
|
|
58
|
+
case "TSObjectKeyword":
|
|
59
|
+
case "TSStringKeyword":
|
|
60
|
+
case "TSSymbolKeyword":
|
|
61
|
+
case "TSUndefinedKeyword":
|
|
62
|
+
case "TSUnknownKeyword":
|
|
63
|
+
case "TSVoidKeyword":
|
|
64
|
+
return node.type;
|
|
65
|
+
case "TSLiteralType": {
|
|
66
|
+
const value = literalValue(node);
|
|
67
|
+
return value === null ? null : `literal(${value})`;
|
|
68
|
+
}
|
|
69
|
+
case "TSArrayType": {
|
|
70
|
+
const element = canonicalType(node.elementType, parameters);
|
|
71
|
+
return element === null ? null : `array(${element})`;
|
|
72
|
+
}
|
|
73
|
+
case "TSParenthesizedType": return canonicalType(node.typeAnnotation, parameters);
|
|
74
|
+
case "TSTypeOperator": {
|
|
75
|
+
const type = canonicalType(node.typeAnnotation, parameters);
|
|
76
|
+
return type === null ? null : `${node.operator}(${type})`;
|
|
77
|
+
}
|
|
78
|
+
case "TSUnionType":
|
|
79
|
+
case "TSIntersectionType": {
|
|
80
|
+
const types = node.types.map((type) => canonicalType(type, parameters));
|
|
81
|
+
if (types.some((type) => type === null))
|
|
82
|
+
return null;
|
|
83
|
+
return `${node.type === "TSUnionType" ? "union" : "intersection"}(${[...new Set(types)].sort().join(",")})`;
|
|
84
|
+
}
|
|
85
|
+
case "TSTypeLiteral": return canonicalMembers(node.members, parameters);
|
|
86
|
+
case "TSTypeReference": {
|
|
87
|
+
const name = canonicalTypeName(node.typeName);
|
|
88
|
+
if (name === null)
|
|
89
|
+
return null;
|
|
90
|
+
const arguments_ = node.typeArguments?.params.map((type) => canonicalType(type, parameters)) ?? [];
|
|
91
|
+
if (arguments_.some((type) => type === null))
|
|
92
|
+
return null;
|
|
93
|
+
return `ref(${parameters.get(name) ?? name}<${arguments_.join(",")}>)`;
|
|
94
|
+
}
|
|
95
|
+
default: return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function canonicalDeclaration(node) {
|
|
99
|
+
const parameters = new Map();
|
|
100
|
+
for (const [index, parameter] of (node.typeParameters?.params ?? []).entries()) {
|
|
101
|
+
parameters.set(parameter.name.name, `$${index}`);
|
|
102
|
+
}
|
|
103
|
+
if (node.type === "TSTypeAliasDeclaration")
|
|
104
|
+
return canonicalType(node.typeAnnotation, parameters);
|
|
105
|
+
if (node.extends.length > 0)
|
|
106
|
+
return null;
|
|
107
|
+
return canonicalMembers(node.body.body, parameters);
|
|
108
|
+
}
|
|
109
|
+
/** Report exact structural duplicates without TypeScript assignability or fuzzy matching. */
|
|
110
|
+
export const noDuplicateTypesRule = defineRule({
|
|
111
|
+
meta: {
|
|
112
|
+
type: "suggestion",
|
|
113
|
+
docs: { description: "Report structurally identical TypeScript declarations" },
|
|
114
|
+
messages: { duplicate: "{{message}} First seen as {{firstName}} in {{firstFile}}." },
|
|
115
|
+
schema: [{ type: "object", properties: { message: { type: "string" }, minProperties: { type: "integer", minimum: 0 } }, additionalProperties: false }],
|
|
116
|
+
},
|
|
117
|
+
createOnce(context) {
|
|
118
|
+
const seen = new Map();
|
|
119
|
+
let options = {};
|
|
120
|
+
const report = (node, fingerprint) => {
|
|
121
|
+
const first = seen.get(fingerprint);
|
|
122
|
+
if (first === undefined) {
|
|
123
|
+
seen.set(fingerprint, { name: node.id.name, filename: context.filename });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
context.report({ node, messageId: "duplicate", data: { message: options.message ?? "This type is structurally identical to an existing declaration.", firstName: first.name, firstFile: first.filename } });
|
|
127
|
+
};
|
|
128
|
+
const inspect = (node) => {
|
|
129
|
+
const fingerprint = canonicalDeclaration(node);
|
|
130
|
+
if (fingerprint === null)
|
|
131
|
+
return;
|
|
132
|
+
const properties = node.type === "TSTypeAliasDeclaration" && node.typeAnnotation.type === "TSTypeLiteral" ? node.typeAnnotation.members.length : node.type === "TSInterfaceDeclaration" ? node.body.body.length : Infinity;
|
|
133
|
+
if (properties < (options.minProperties ?? 2))
|
|
134
|
+
return;
|
|
135
|
+
report(node, fingerprint);
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
Program() { options = context.options[0] ?? {}; },
|
|
139
|
+
TSTypeAliasDeclaration: inspect,
|
|
140
|
+
TSInterfaceDeclaration: inspect,
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-deslop",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Opinionated Oxlint rules that reject low-evidence, low-signal, AI-slop code patterns.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"prepublishOnly": "npm run build",
|
|
20
20
|
"check": "npm run build && oxlint src && tsc --noEmit",
|
|
21
21
|
"lint": "oxlint src",
|
|
22
|
+
"test": "vitest run",
|
|
22
23
|
"typecheck": "tsc --noEmit"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/node": "26.2.0",
|
|
39
40
|
"oxlint": "1.82.0",
|
|
40
|
-
"typescript": "7.0.2"
|
|
41
|
+
"typescript": "7.0.2",
|
|
42
|
+
"vitest": "^5.0.1"
|
|
41
43
|
},
|
|
42
44
|
"license": "MIT",
|
|
43
45
|
"repository": {
|