Scaffold oxlint plugin with initial rule#2603
Conversation
- Introduce a t3code oxlint plugin and wire it into repo linting - Flag Effect Schema compiler calls inside function bodies - Add fixture-based tests for valid and invalid cases Co-authored-by: codex <codex@users.noreply.github.com>
- Switch to explicit Effect module imports - Encode Oxlint config with Schema - Simplify test assertions and harness signatures
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
ApprovabilityVerdict: Approved Scaffolds a new oxlint plugin with mechanical refactors across the codebase to hoist schema compiler calls to module scope. Changes are purely structural with no runtime behavior modifications. Unresolved comments are low-severity style concerns about the lint rule itself. You can customize Macroscope's approvability policy. Learn more. |
Co-authored-by: codex <codex@users.noreply.github.com>
Dismissing prior approval to re-evaluate 3dd82e2
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Lint rule falsely treats dynamic member accesses as static
- Fixed isStaticSchemaReference to traverse MemberExpression chains and only classify them as static when the root object is a capitalized identifier, preventing false positives on dynamic accesses like input.schema.
Or push these changes by commenting:
@cursor push 6ca33a3e1a
Preview (6ca33a3e1a)
diff --git a/oxlint-plugin-t3code/rules/no-inline-schema-compile.test.ts b/oxlint-plugin-t3code/rules/no-inline-schema-compile.test.ts
--- a/oxlint-plugin-t3code/rules/no-inline-schema-compile.test.ts
+++ b/oxlint-plugin-t3code/rules/no-inline-schema-compile.test.ts
@@ -54,6 +54,16 @@
`,
);
+ rule.valid(
+ "allows dynamic member access on function parameters",
+ `
+ import { Schema } from "effect";
+
+ export const parseWith = (input: { schema: Schema.Codec<any, any> }, value: unknown) =>
+ Schema.decodeUnknownEffect(input.schema)(value);
+ `,
+ );
+
rule.invalid(
"reports schema compilers inside function bodies",
`
diff --git a/oxlint-plugin-t3code/rules/no-inline-schema-compile.ts b/oxlint-plugin-t3code/rules/no-inline-schema-compile.ts
--- a/oxlint-plugin-t3code/rules/no-inline-schema-compile.ts
+++ b/oxlint-plugin-t3code/rules/no-inline-schema-compile.ts
@@ -46,16 +46,30 @@
);
};
+const isCapitalizedIdentifier = (node: unknown): boolean => {
+ const expression = unwrapExpression(node);
+ if (Option.isNone(expression) || expression.value.type !== "Identifier") return false;
+ const [firstChar] = expression.value.name;
+ return firstChar !== undefined && firstChar.toUpperCase() === firstChar;
+};
+
const isStaticSchemaReference = (node: unknown): boolean => {
const expression = unwrapExpression(node);
if (Option.isNone(expression)) return false;
if (expression.value.type === "Identifier") {
- const [firstChar] = expression.value.name;
- return firstChar !== undefined && firstChar.toUpperCase() === firstChar;
+ return isCapitalizedIdentifier(node);
}
- return expression.value.type === "MemberExpression";
+ if (expression.value.type === "MemberExpression") {
+ let current: Option.Option<{ type: string; object?: unknown }> = expression;
+ while (Option.isSome(current) && current.value.type === "MemberExpression") {
+ current = unwrapExpression(current.value.object);
+ }
+ return Option.isSome(current) && isCapitalizedIdentifier(current.value);
+ }
+
+ return false;
};
const isNestedStaticSchemaCall = (node: unknown): boolean => {You can send follow-ups to the cloud agent here.
| } | ||
|
|
||
| return expression.value.type === "MemberExpression"; | ||
| }; |
There was a problem hiding this comment.
Lint rule falsely treats dynamic member accesses as static
Low Severity
isStaticSchemaReference returns true for any MemberExpression, but not all member expressions are static/hoistable. A dynamic property access like input.schema or options.schema (where the object is a function parameter) would be incorrectly classified as a static reference. This causes the rule to warn about code that cannot actually be hoisted to module scope, since the schema is only known at call time. The test suite only covers the simple Identifier case for dynamic schemas (lowercase schema), missing this MemberExpression edge case.
Reviewed by Cursor Bugbot for commit 3dd82e2. Configure here.
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Identical helper function duplicated across three files
- Extracted the duplicated encodeJsonStringForDiagnostics function and its encodeUnknownJsonStringExit constant into @t3tools/shared/schemaJson, then updated all three consuming files to import from the shared module.
Or push these changes by commenting:
@cursor push a4a2302607
You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit e9f5490. Configure here.



Note
Medium Risk
Broad mechanical refactors touch runtime code paths (providers, orchestration, text generation) by changing how/where Schema decoders/encoders are constructed and invoked; while intended to be behavior-preserving, subtle decode/encode or error-handling differences could surface at runtime. The new lint rule itself is low-risk but may introduce new warnings and enforcement expectations across the repo.
Overview
Adds a new workspace
oxlint-plugin-t3codeand registers it in.oxlintrc.json, introducingt3code/no-inline-schema-compileto warn whenSchema.*decoder/encoder/predicate compilers are created and immediately invoked inside function bodies instead of being hoisted.Updates the repo to
oxlint@^1.63.0(and adds@oxlint/plugins) and applies the rule’s guidance across the codebase by hoisting manySchema.decode*/Schema.encode*/Schema.ishelpers to module scope and reusing them, including safer diagnostic JSON serialization paths that avoid throwing when encoding fails.Reviewed by Cursor Bugbot for commit e9f5490. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add oxlint plugin with
no-inline-schema-compilerule and hoist Schema compilers to module scopeoxlint-plugin-t3codeworkspace package (index.ts) with theno-inline-schema-compilerule (no-inline-schema-compile.ts) that warns when Effect Schema compiler calls (e.g.Schema.decodeUnknownEffect) are immediately invoked inside function bodies with static schemas instead of being hoisted to module scope.warnseverity and disableseslint/no-underscore-dangle.Schema.decodeSync(Foo)(value)/Schema.is(Foo)(value)call patterns with module-scope cached decoders and type guards.ClaudeAdapter,CursorAdapter, and text generation layers where sync schema encoding could throw on non-serializable inputs; these now return fallback strings or surface structuredTextGenerationErrorvalues instead.Macroscope summarized e9f5490.