chore: effect pattern lint infrastructure (#35210)

This commit is contained in:
Kit Langton 2026-07-03 13:58:26 -04:00 committed by GitHub
commit 1401901529
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
70 changed files with 524 additions and 234 deletions

View file

@ -0,0 +1,12 @@
id: no-drizzle-column-name
snapshots:
? |
const table = sqliteTable("session", {
projectID: text("project_id").notNull(),
createdAt: integer("time_created").notNull(),
})
: labels:
- source: text("project_id")
style: primary
start: 52
end: 70

View file

@ -0,0 +1,30 @@
id: no-effect-die-string
snapshots:
Effect.die("boom"):
labels:
- source: Effect.die("boom")
style: primary
start: 0
end: 18
- source: '"boom"'
style: secondary
start: 11
end: 17
- source: ("boom")
style: secondary
start: 10
end: 18
Effect.die(`boom ${value}`):
labels:
- source: Effect.die(`boom ${value}`)
style: primary
start: 0
end: 27
- source: '`boom ${value}`'
style: secondary
start: 11
end: 26
- source: (`boom ${value}`)
style: secondary
start: 10
end: 27

View file

@ -0,0 +1,42 @@
id: no-import-alias
snapshots:
import { baz, foo as bar } from "./foo":
labels:
- source: foo as bar
style: primary
start: 14
end: 24
- source: bar
style: secondary
start: 21
end: 24
import { foo as bar } from "./foo":
labels:
- source: foo as bar
style: primary
start: 9
end: 19
- source: bar
style: secondary
start: 16
end: 19
import { foo as bar, baz } from "./foo":
labels:
- source: foo as bar
style: primary
start: 9
end: 19
- source: bar
style: secondary
start: 16
end: 19
import { type Foo as Bar, baz } from "./foo":
labels:
- source: type Foo as Bar
style: primary
start: 9
end: 24
- source: Bar
style: secondary
start: 21
end: 24

View file

@ -0,0 +1,8 @@
id: no-json-parse-cast
snapshots:
const value = JSON.parse(input) as Record<string, unknown>:
labels:
- source: JSON.parse(input) as Record<string, unknown>
style: primary
start: 14
end: 58

View file

@ -0,0 +1,20 @@
id: no-nested-effect-service-yield
snapshots:
? |
Effect.gen(function* () {
yield* (yield* Foo.Service).client.run()
})
: labels:
- source: (yield* Foo.Service).client.run()
style: primary
start: 35
end: 68
? |
Effect.gen(function* () {
yield* (yield* Foo.Service).run()
})
: labels:
- source: (yield* Foo.Service).run()
style: primary
start: 35
end: 61

View file

@ -0,0 +1,22 @@
id: no-star-import
snapshots:
import * as Foo from "./foo":
labels:
- source: '* as Foo'
style: primary
start: 7
end: 15
- source: import * as Foo from "./foo"
style: secondary
start: 0
end: 28
import type * as Foo from "./foo":
labels:
- source: '* as Foo'
style: primary
start: 12
end: 20
- source: import type * as Foo from "./foo"
style: secondary
start: 0
end: 33

View file

@ -0,0 +1,14 @@
id: no-drizzle-column-name
valid:
- |
const table = sqliteTable("session", {
project_id: text().notNull(),
time_created: integer().notNull(),
payload: text({ mode: "json" }),
})
invalid:
- |
const table = sqliteTable("session", {
projectID: text("project_id").notNull(),
createdAt: integer("time_created").notNull(),
})

View file

@ -0,0 +1,7 @@
id: no-effect-die-string
valid:
- Effect.die(new Error("boom"))
- Effect.fail("boom")
invalid:
- Effect.die("boom")
- Effect.die(`boom ${value}`)

View file

@ -0,0 +1,13 @@
id: no-import-alias
valid:
- import { foo } from "./foo"
- import type { Foo } from "./foo"
- import foo from "./foo"
- export { foo as bar } from "./foo"
- import type { Plugin as EffectPlugin } from "./foo"
- import type { Foo as Bar, Baz } from "./foo"
invalid:
- import { foo as bar } from "./foo"
- import { baz, foo as bar } from "./foo"
- import { foo as bar, baz } from "./foo"
- import { type Foo as Bar, baz } from "./foo"

View file

@ -0,0 +1,6 @@
id: no-json-parse-cast
valid:
- const value = JSON.parse(input)
- const value = Schema.decodeUnknownOption(Schema.UnknownFromJsonString)(input)
invalid:
- const value = JSON.parse(input) as Record<string, unknown>

View file

@ -0,0 +1,21 @@
id: no-nested-effect-service-yield
valid:
- |
Effect.gen(function* () {
const service = yield* Foo.Service
yield* service.run()
})
- |
Effect.gen(function* () {
const db = (yield* Database.Service).db
yield* db.run()
})
invalid:
- |
Effect.gen(function* () {
yield* (yield* Foo.Service).run()
})
- |
Effect.gen(function* () {
yield* (yield* Foo.Service).client.run()
})

View file

@ -0,0 +1,8 @@
id: no-star-import
valid:
- import { Foo } from "./foo"
- import Foo from "./foo"
- export * as Foo from "./foo"
invalid:
- import * as Foo from "./foo"
- import type * as Foo from "./foo"

View file

@ -0,0 +1,22 @@
id: no-drizzle-column-name
language: TypeScript
message: Use snake_case object keys instead of explicit drizzle column names.
severity: error
files:
- packages/core/src/**/sql.ts
- packages/core/src/**/*.sql.ts
rule:
any:
- pattern: text($NAME)
- pattern: text($NAME, $$$ARGS)
- pattern: integer($NAME)
- pattern: integer($NAME, $$$ARGS)
- pattern: blob($NAME)
- pattern: blob($NAME, $$$ARGS)
- pattern: real($NAME)
- pattern: real($NAME, $$$ARGS)
- pattern: numeric($NAME)
- pattern: numeric($NAME, $$$ARGS)
constraints:
NAME:
kind: string

View file

@ -0,0 +1,22 @@
id: no-effect-die-string
language: TypeScript
message: die with `new Error(...)`.
severity: error
rule:
any:
- all:
- pattern: Effect.die($MESSAGE)
- has:
field: arguments
all:
- kind: arguments
- has:
kind: string
- all:
- pattern: Effect.die($MESSAGE)
- has:
field: arguments
all:
- kind: arguments
- has:
kind: template_string

View file

@ -0,0 +1,14 @@
id: no-import-alias
language: TypeScript
message: Do not alias value imports. For type name collisions, alias inside a dedicated `import type` statement.
severity: error
rule:
all:
- kind: import_specifier
- has:
field: alias
kind: identifier
- not:
inside:
pattern: import type { $$$SPECS } from "$MOD"
stopBy: end

View file

@ -0,0 +1,10 @@
id: no-star-import
language: TypeScript
message: Do not use star imports.
severity: error
rule:
all:
- kind: namespace_import
- inside:
kind: import_statement
stopBy: end

View file

@ -0,0 +1,4 @@
ruleDirs:
- rules
testConfigs:
- testDir: rule-tests