@felixarntz/biome 0.1.1 → 0.2.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 CHANGED
@@ -2,12 +2,20 @@
2
2
 
3
3
  Reusable [Biome](https://biomejs.dev) lint rules that make your agent produce better code in fewer review cycles, written as [GritQL plugins](https://biomejs.dev/linter/plugins/). Install the package once and reference the rules from any project's Biome config — either all of them with a single line, or individually as needed — without copying `.grit` files around.
4
4
 
5
+ Rules cover aspects like type-safety escape hatches, prototype-chain-safe property access and iteration, safer dynamic-key object construction, and self-documenting function APIs.
6
+
5
7
  ## Rules
6
8
 
7
9
  | Rule | What it flags |
8
10
  | --- | --- |
9
11
  | `no-as-unknown-as` | `value as unknown as T` double assertions, which bypass TypeScript's type checking entirely. |
10
- | `no-in-operator` | The `in` operator, recommending `Object.hasOwn(obj, prop)` (which does not walk the prototype chain). |
12
+ | `no-empty-object-accumulator` | `.reduce(..., {})` accumulator seeds, recommending `Object.create(null)` or `Map` for dynamic-key aggregation. |
13
+ | `no-has-own-property` | Direct `obj.hasOwnProperty(key)` calls, recommending `Object.hasOwn(obj, key)` because the method can be missing or shadowed. |
14
+ | `no-in-operator` | The `in` operator and `for...in`, recommending own-property checks and own-key iteration that do not walk the prototype chain. |
15
+ | `no-object-assign-target` | `Object.assign({}, ...)` plain-object merge targets, recommending `Object.assign(Object.create(null), ...)`. |
16
+ | `no-object-from-entries` | `Object.fromEntries(...)`, which creates a plain object with `Object.prototype` for dynamic keys. |
17
+ | `no-prototype-mutation` | `Object.setPrototypeOf(...)` and `Reflect.setPrototypeOf(...)`, which mutate prototype chains. |
18
+ | `no-prototype-property-access` | Direct `obj.__proto__` and `obj.constructor.prototype` access, which are common prototype-pollution primitives. |
11
19
  | `prefer-object-parameter` | Functions, methods, and constructors with more than one positional parameter, recommending a single object argument with named parameters instead. A leading TypeScript `this` parameter is not counted. Inline callbacks, whose signature is dictated by the calling API, are left alone. |
12
20
 
13
21
  ## Installation
@@ -39,8 +47,14 @@ Some of the rules are more opinionated than others. So if you don't want to use
39
47
  {
40
48
  "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
41
49
  "plugins": [
42
- "./node_modules/@felixarntz/biome/rules/no-in-operator.grit",
43
50
  "./node_modules/@felixarntz/biome/rules/no-as-unknown-as.grit",
51
+ "./node_modules/@felixarntz/biome/rules/no-empty-object-accumulator.grit",
52
+ "./node_modules/@felixarntz/biome/rules/no-has-own-property.grit",
53
+ "./node_modules/@felixarntz/biome/rules/no-in-operator.grit",
54
+ "./node_modules/@felixarntz/biome/rules/no-object-assign-target.grit",
55
+ "./node_modules/@felixarntz/biome/rules/no-object-from-entries.grit",
56
+ "./node_modules/@felixarntz/biome/rules/no-prototype-mutation.grit",
57
+ "./node_modules/@felixarntz/biome/rules/no-prototype-property-access.grit",
44
58
  "./node_modules/@felixarntz/biome/rules/prefer-object-parameter.grit"
45
59
  ]
46
60
  }
@@ -54,7 +68,7 @@ Some of the rules are more opinionated than others. So if you don't want to use
54
68
 
55
69
  ## `Object.hasOwn` type augmentation
56
70
 
57
- `no-in-operator` steers you toward `Object.hasOwn`, but the built-in TypeScript signature returns a plain `boolean` and therefore doesn't narrow the checked object. This package ships a type augmentation that restores narrowing parity with the `in` operator.
71
+ `no-in-operator` and `no-has-own-property` steer you toward `Object.hasOwn`, but the built-in TypeScript signature returns a plain `boolean` and therefore doesn't narrow the checked object. This package ships a type augmentation that restores narrowing parity with the `in` operator.
58
72
 
59
73
  Enable it by importing it once from any `.ts`/`.d.ts` file that is part of your compilation:
60
74
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@felixarntz/biome",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Reusable Biome (GritQL) lint rules that make your agent produce better code in fewer review cycles.",
5
5
  "license": "MIT",
6
6
  "keywords": [
package/rules/all.grit CHANGED
@@ -7,8 +7,36 @@ or {
7
7
  `$value as unknown as $type` as $expr where {
8
8
  register_diagnostic(span=$expr, message="Avoid `as unknown as $type`. Double assertions through `unknown` bypass TypeScript's type checking entirely. Fix the underlying type mismatch instead.")
9
9
  },
10
- `$prop in $obj` as $expr where {
11
- register_diagnostic(span=$expr, message="Use `Object.hasOwn($obj, $prop)` instead of the `in` operator. `in` also walks the prototype chain, which is rarely the intended runtime check.")
10
+ `$items.reduce($reducer, {})` as $call where {
11
+ register_diagnostic(span=$call, message="Use `Object.create(null)` or `new Map()` instead of `{}` as a reducer accumulator. Plain object accumulators have a prototype chain that can leak into dynamic-key aggregation.")
12
+ },
13
+ `$obj.hasOwnProperty($...)` as $call where {
14
+ register_diagnostic(span=$call, message="Use `Object.hasOwn($obj, key)` instead of calling `hasOwnProperty()` on the object. The method can be missing on null-prototype objects or shadowed by user-controlled properties.")
15
+ },
16
+ or {
17
+ `$prop in $obj` as $expr,
18
+ JsForInStatement() as $expr
19
+ } where {
20
+ register_diagnostic(span=$expr, message="Avoid prototype-chain property checks and iteration. Use `Object.hasOwn($obj, $prop)` instead of the `in` operator, and `Object.keys()` or `Object.entries()` with `for...of` instead of `for...in`.")
21
+ },
22
+ `Object.assign($target, $...)` as $call where {
23
+ $target <: `{}`,
24
+ register_diagnostic(span=$call, message="Use `Object.assign(Object.create(null), ...)` instead of `Object.assign({}, ...)`. A plain object merge target has a prototype chain that can preserve prototype-pollution risk.")
25
+ },
26
+ `Object.fromEntries($...)` as $call where {
27
+ register_diagnostic(span=$call, message="Avoid `Object.fromEntries()` for dynamic keys. It creates a plain object with `Object.prototype`; use `Map`, a null-prototype helper, or explicit assignment into `Object.create(null)` instead.")
28
+ },
29
+ or {
30
+ `Object.setPrototypeOf($...)` as $call,
31
+ `Reflect.setPrototypeOf($...)` as $call
32
+ } where {
33
+ register_diagnostic(span=$call, message="Avoid mutating prototype chains with `setPrototypeOf()`. Prefer creating the intended shape up front with `Object.create(null)` or an explicit class/object model.")
34
+ },
35
+ or {
36
+ `$obj.__proto__` as $access,
37
+ `$obj.constructor.prototype` as $access
38
+ } where {
39
+ register_diagnostic(span=$access, message="Avoid direct prototype access through `__proto__` or `constructor.prototype`. These property paths are common prototype-pollution primitives; use explicit prototype APIs only in audited code.")
12
40
  },
13
41
  // Every arm below binds $params to a parameter items list, then the shared
14
42
  // trailing where applies one multi-positional check and emits the diagnostic.
@@ -0,0 +1,5 @@
1
+ language js
2
+
3
+ `$items.reduce($reducer, {})` as $call where {
4
+ register_diagnostic(span=$call, message="Use `Object.create(null)` or `new Map()` instead of `{}` as a reducer accumulator. Plain object accumulators have a prototype chain that can leak into dynamic-key aggregation.")
5
+ }
@@ -0,0 +1,5 @@
1
+ language js
2
+
3
+ `$obj.hasOwnProperty($...)` as $call where {
4
+ register_diagnostic(span=$call, message="Use `Object.hasOwn($obj, key)` instead of calling `hasOwnProperty()` on the object. The method can be missing on null-prototype objects or shadowed by user-controlled properties.")
5
+ }
@@ -1,5 +1,8 @@
1
1
  language js
2
2
 
3
- `$prop in $obj` as $expr where {
4
- register_diagnostic(span=$expr, message="Use `Object.hasOwn($obj, $prop)` instead of the `in` operator. `in` also walks the prototype chain, which is rarely the intended runtime check.")
3
+ or {
4
+ `$prop in $obj` as $expr,
5
+ JsForInStatement() as $expr
6
+ } where {
7
+ register_diagnostic(span=$expr, message="Avoid prototype-chain property checks and iteration. Use `Object.hasOwn($obj, $prop)` instead of the `in` operator, and `Object.keys()` or `Object.entries()` with `for...of` instead of `for...in`.")
5
8
  }
@@ -0,0 +1,6 @@
1
+ language js
2
+
3
+ `Object.assign($target, $...)` as $call where {
4
+ $target <: `{}`,
5
+ register_diagnostic(span=$call, message="Use `Object.assign(Object.create(null), ...)` instead of `Object.assign({}, ...)`. A plain object merge target has a prototype chain that can preserve prototype-pollution risk.")
6
+ }
@@ -0,0 +1,5 @@
1
+ language js
2
+
3
+ `Object.fromEntries($...)` as $call where {
4
+ register_diagnostic(span=$call, message="Avoid `Object.fromEntries()` for dynamic keys. It creates a plain object with `Object.prototype`; use `Map`, a null-prototype helper, or explicit assignment into `Object.create(null)` instead.")
5
+ }
@@ -0,0 +1,8 @@
1
+ language js
2
+
3
+ or {
4
+ `Object.setPrototypeOf($...)` as $call,
5
+ `Reflect.setPrototypeOf($...)` as $call
6
+ } where {
7
+ register_diagnostic(span=$call, message="Avoid mutating prototype chains with `setPrototypeOf()`. Prefer creating the intended shape up front with `Object.create(null)` or an explicit class/object model.")
8
+ }
@@ -0,0 +1,8 @@
1
+ language js
2
+
3
+ or {
4
+ `$obj.__proto__` as $access,
5
+ `$obj.constructor.prototype` as $access
6
+ } where {
7
+ register_diagnostic(span=$access, message="Avoid direct prototype access through `__proto__` or `constructor.prototype`. These property paths are common prototype-pollution primitives; use explicit prototype APIs only in audited code.")
8
+ }