@systemfsoftware/oxlint-plugin-effect-schema
v6.0.0
Published
Oxlint rules for Effect Schema declarations: tagged errors and schema file shape.
Maintainers
Readme
@systemfsoftware/oxlint-plugin-effect-schema
Oxlint rules for Effect Schema declarations — how a schema is declared and what a *.schema.ts may export.
Rules
| Rule | What it enforces |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ban-data-taggederror | Use Schema.TaggedError, never Data.TaggedError. |
| no-manual-tag-member | A type alias, interface, or type literal must not declare a _tag property signature; derive the type from TaggedStruct / TaggedError with Schema.Type, or inherit it from a tag carrier. |
| no-manual-tag-property | A class must not declare its own _tag; use TaggedClass / TaggedError. |
| schema-declaration-location | A schema declaration (a class extending a Schema factory, or a module-scope const initialized to a Schema.<member>(...) call) must live in a *.schema.ts file or the <stem>.workflow.ts that owns it. |
| schema-file-exports-schemas-only | A *.schema.ts may export only its own schemas: schema declarations plus the type vocabulary (type aliases, interfaces, enums, type-only namespaces) the schemas are built from, the type-identity symbols (Symbol.for('...')) that name a type at runtime, and operations whose declared parameter or return type names one of those same-file types — read through a union or intersection member, a type predicate target, a type parameter's extends constraint or a readonly T[] element — declared on the function or in a const's declarator annotation (the dual shape). A const whose declarator annotation names one of those same-file types is data of that type and is admitted too. An exported function or call-initialized const with no explicit annotations, or one whose function return or const annotation names an Effect, Stream or Layer carrier, is banned — annotations name the type the operation serves, and a live computation belongs to a handle, service or workflow. An exported codec const (S.encodeSync, S.decodeSync, Arbitrary.schema, ...) and every re-export form are banned — the file declares its schemas, the caller applies them at the point of use. |
| schema-file-imports-pure-modules-only | A *.schema.ts may value-import only pure modules: Effect's pure data modules, its schema family, effect/Effect for fallible getters, the arbitrary module a toCodecArbitrary annotation needs, sibling *.schema.ts files and @systemfsoftware/* packages. Node builtins, other third-party packages and local non-schema modules are reported; type-only imports are free. |
| schema-filter-constructive-generation | A filter consumed by .check() — in member, destructured, or named-import form — or exported from a module carries constructive-generation metadata: arbitraryConstraint on scalar filters, an explicit arbitrary: { residual: true } declaration for dense struct-level invariants that generate fine by rejection sampling, or a move to Schema.declare with toCodecArbitrary for sparse invariants. Scalar chains with inert node-level overrides report filterDiscards; struct filters without metadata or the residual marker report filterResidualUndeclared. The override silencer fires only when the receiver terminates at Schema.declare. A filter without these generates by discarding with the real generator living outside the schema. Imported non-exported filters are trusted; exported filters must carry their metadata at home. |
| schema-checked-element-named | A checked schema node passed inline as a collection combinator element must live in a named module-scope declaration, so the invariant has one home for its constructive metadata and its tests. |
| schema-recursive-union-budget | A recursive union whose cycle carries six or more Schema.suspend members derives arbitrary values superlinearly — measured 8 ms at four members, 222 ms at six, 52.6 s at eight — so it must hoist to a single Schema.suspend at the recursion point and declare its ceiling with recursionBudget. A recursion point whose suspension returns a union that reaches itself and declares neither recursionBudget nor a toCodecArbitrary derivation is the same verdict one shape later. A cycle built by a call that does not resolve to the Schema vocabulary (any local builder) is a trusted builder. The verdict comes from one file's own value graph, so a cycle closed through an import, recursion carried by a Schema.declare type parameter, and suspends written inline in the member list all stay silent. |
| tagged-error-requires-message | Every production class extending Schema.TaggedError must declare a message — a message getter on the class or a message field in its schema fields. Test files, tests/, __tests__/ and __fixtures__/ are exempt. A message-less class prints an empty failure headline, so the rule fails it. |
Enrollment
Turned on by @systemfsoftware/oxlint-config/base, which spreads configs.recommended.rules.
Testing
Each rule ships a RuleTester suite at src/rules/__tests__/<rule>.test.ts, with 100% mutation coverage required.
