Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b7acdec
feat: add Solid framework rules ported from eslint-plugin-solid
cursoragent May 27, 2026
d674b0a
refactor(solid): consolidate duplicated helpers per AGENTS.md DRY rule
cursoragent May 27, 2026
1452f07
fix(solid-jsx-no-script-url): replace control-character regex with ex…
cursoragent May 27, 2026
4c00c68
docs(solid-no-innerhtml): correct port comment about static-string ha…
cursoragent May 27, 2026
224a3cc
feat(solid): add 7 new react-doctor-original rules + enhance 4 existing
aidenybai May 27, 2026
9a70a85
fix(solid): address Bugbot findings — DRY isSetterCall, prototype-pol…
aidenybai May 27, 2026
e6dece1
fix(solid): add receiver check for console methods, extract shared ex…
aidenybai May 27, 2026
f81be90
fix(solid-no-react-specific-props): gate className/htmlFor check on D…
aidenybai May 27, 2026
7bc57fb
feat(solid): add 7 new docs/community-derived rules
aidenybai May 27, 2026
d62a89f
refactor: deduplicate isDomElementName in isJsxAttributeOnIntrinsicHt…
aidenybai May 27, 2026
9182f23
chore: format .agents/skills SKILL.md files
aidenybai May 27, 2026
32163e5
feat(solid): port reactivity rule and jsx-no-undef from oxlint-plugin…
aidenybai May 27, 2026
88e0585
test(solid): add tests for 9 previously untested rules
aidenybai May 27, 2026
0b788e9
fix(solid): close parity gaps with upstream oxlint-plugin-solidjs
aidenybai May 27, 2026
0685e7d
feat(solid): implement validate-jsx-nesting from scratch
aidenybai May 27, 2026
cf9cbf8
feat(solid): implement jsx-uses-vars for use:directive tracking
aidenybai May 27, 2026
7991afe
fix(solid-reactivity): consume references to prevent duplicate report…
aidenybai May 27, 2026
f371406
fix(solid): resolve Bugbot findings — style-prop line-height FP, effe…
aidenybai May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .agents/skills/rule-research/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Goal:
Find examples where <exact bug definition>.

Return:

- Strong positive examples
- Pattern-adjacent examples
- False-positive traps
Expand All @@ -93,24 +94,31 @@ Detector precision:
Syntax-only | scope-aware | path-aware

Evidence:

- <docs, OSS, issue, RDE, or similar-tool evidence>

Strong positives:

- <exact reportable examples>

False-positive traps:

- <valid examples that must stay quiet>

In scope for v1:

- <supported cases>

Out of scope for v1:

- <explicit non-goals>

Test seeds:

- <invalid and valid fixture ideas>

Open questions:

- <only questions that affect correctness or scope>
```

Expand Down
21 changes: 13 additions & 8 deletions .agents/skills/rule-validate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,13 @@ Catches <specific issue>.
<Runtime reason in 1-3 sentences.>

Before:

```tsx
<bad example>
```

After:

```tsx
<good example>
```
Expand All @@ -115,14 +117,14 @@ After:

## Eval results

| Check | Result |
| --- | --- |
| Repos scanned | `<distinct repo count>` |
| RootDir scans | `<manifest/rootDir entries>` |
| Target rule | `<rule-name>` |
| Diagnostics | `<target-rule diagnostics>` |
| False positives found | `<count after manual inspection>` |
| Output artifact | `<filtered JSONL or summary path>` |
| Check | Result |
| --------------------- | ---------------------------------- |
| Repos scanned | `<distinct repo count>` |
| RootDir scans | `<manifest/rootDir entries>` |
| Target rule | `<rule-name>` |
| Diagnostics | `<target-rule diagnostics>` |
| False positives found | `<count after manual inspection>` |
| Output artifact | `<filtered JSONL or summary path>` |

## Test plan

Expand Down Expand Up @@ -150,15 +152,18 @@ Return:

```md
Validation summary:

- <commands and results>
- <implementation review findings>
- <RDE summary or skip reason>
- <false positives found and fixed>
- <regression tests added>

PR-ready notes:

- <Why/What/Test plan highlights>

Residual risk:

- <known v1 non-goals or unchecked areas>
```
5 changes: 5 additions & 0 deletions .agents/skills/rule-writing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,23 @@ When the writing stage is done, report:

```md
Implemented:

- <rule, tests, registry, utilities>

Detector behavior:

- <what reports>
- <what intentionally stays quiet>

Validation run:

- <focused tests/checks>

Known v1 non-goals:

- <unsupported cases preserved from the rule contract>

Next stage:

- Run `rule-validate`.
```
2 changes: 2 additions & 0 deletions packages/core/src/project-info/discover-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { findMonorepoRoot, isMonorepoRoot } from "./find-monorepo-root.js";
import { findReactInWorkspaces } from "./find-react-in-workspaces.js";
import { getDependencyDeclaration } from "./utils/get-dependency-declaration.js";
import { hasReactNativeWorkspaceAnywhere } from "./has-react-native-workspace-anywhere.js";
import { hasSolid } from "./has-solid.js";
import { hasTanStackQuery } from "./has-tanstack-query.js";
import { readPackageJson } from "./read-package-json.js";
import { isCatalogReference, resolveCatalogVersion } from "./resolve-catalog-version.js";
Expand Down Expand Up @@ -166,6 +167,7 @@ export const discoverProject = (directory: string): ProjectInfo => {
hasTypeScript,
hasReactCompiler: detectReactCompiler(directory, packageJson),
hasTanStackQuery: hasTanStackQuery(packageJson),
hasSolid: hasSolid(packageJson),
hasReactNativeWorkspace,
sourceFileCount,
};
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/project-info/has-solid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { PackageJson } from "../types/index.js";

const SOLID_PACKAGES = new Set(["solid-js", "solid-start", "@solidjs/start", "@solidjs/router"]);

export const hasSolid = (packageJson: PackageJson): boolean => {
const allDependencies = {
...packageJson.peerDependencies,
...packageJson.dependencies,
...packageJson.devDependencies,
};
return Object.keys(allDependencies).some((packageName) => SOLID_PACKAGES.has(packageName));
};
1 change: 1 addition & 0 deletions packages/core/src/runners/oxlint/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const buildCapabilities = (project: ProjectInfo): ReadonlySet<string> =>

if (project.hasReactCompiler) capabilities.add("react-compiler");
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
if (project.hasSolid) capabilities.add("solid");
if (project.hasTypeScript) capabilities.add("typescript");

return capabilities;
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/types/project-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ export interface ProjectInfo {
hasTypeScript: boolean;
hasReactCompiler: boolean;
hasTanStackQuery: boolean;
/**
* `true` when the project (or any of its workspace packages) declares
* `solid-js` (or `@solidjs/start`, `solid-start`, `@solidjs/router`)
* as a dependency. Enables the `solid` capability — and therefore
* every `solid-*` rule — even on monorepos where the entry-point
* `package.json` is a different framework but a sibling workspace
* (`apps/solid`, `packages/solid-ui`) targets SolidJS.
*
* `false` collapses the gate to "no Solid here" — no `solid-*` rule
* loads for the project at all.
*/
hasSolid: boolean;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasSolid doc comment claims unimplemented workspace traversal

Medium Severity

The doc comment on hasSolid explicitly states it detects Solid "even on monorepos where the entry-point package.json is a different framework but a sibling workspace targets SolidJS." However, hasSolid(packageJson) only inspects the single passed-in package.json — there is no workspace traversal logic (unlike hasReactNativeWorkspaceAnywhere for the analogous hasReactNativeWorkspace field). In monorepos where Solid lives only in a child workspace, the solid capability will never be set and all Solid rules will be silently skipped.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8bf6334. Configure here.

/**
* `true` when the project (or any of its workspace packages) declares
* React Native or Expo as a dependency. Enables the `react-native`
Expand Down
1 change: 1 addition & 0 deletions packages/core/tests/run-inspect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const sampleProject: ProjectInfo = {
hasTypeScript: true,
hasReactCompiler: false,
hasTanStackQuery: false,
hasSolid: false,
hasReactNativeWorkspace: false,
sourceFileCount: 1,
};
Expand Down
1 change: 1 addition & 0 deletions packages/core/tests/services/linter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const sampleProject: ProjectInfo = {
hasTypeScript: true,
hasReactCompiler: false,
hasTanStackQuery: false,
hasSolid: false,
hasReactNativeWorkspace: false,
sourceFileCount: 1,
};
Expand Down
1 change: 1 addition & 0 deletions packages/core/tests/services/project.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const sampleProject: ProjectInfo = {
hasTypeScript: true,
hasReactCompiler: false,
hasTanStackQuery: false,
hasSolid: false,
hasReactNativeWorkspace: false,
sourceFileCount: 1,
};
Expand Down
3 changes: 3 additions & 0 deletions packages/eslint-plugin-react-doctor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import oxlintPlugin, {
NEXTJS_RULES,
REACT_NATIVE_RULES,
RECOMMENDED_RULES,
SOLID_RULES,
TANSTACK_QUERY_RULES,
TANSTACK_START_RULES,
} from "oxlint-plugin-react-doctor";
Expand Down Expand Up @@ -47,6 +48,7 @@ interface EslintPlugin {
"react-native": EslintFlatConfig;
"tanstack-start": EslintFlatConfig;
"tanstack-query": EslintFlatConfig;
solid: EslintFlatConfig;
all: EslintFlatConfig;
};
}
Expand Down Expand Up @@ -99,6 +101,7 @@ const eslintPlugin: EslintPlugin = {
"react-native": buildFlatConfig("react-native", REACT_NATIVE_RULES),
"tanstack-start": buildFlatConfig("tanstack-start", TANSTACK_START_RULES),
"tanstack-query": buildFlatConfig("tanstack-query", TANSTACK_QUERY_RULES),
solid: buildFlatConfig("solid", SOLID_RULES),
all: buildFlatConfig("all", ALL_REACT_DOCTOR_RULES),
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const BUCKET_TO_FRAMEWORK = {
"react-native": "react-native",
"tanstack-start": "tanstack-start",
"tanstack-query": "tanstack-query",
solid: "solid",
};

// Bucket directory → behavioral tags merged onto every rule in that
Expand All @@ -37,6 +38,7 @@ const BUCKET_TO_FRAMEWORK = {
const BUCKET_TO_AUTO_TAGS = {
"react-native": ["react-native"],
server: ["server-action"],
solid: ["solid"],
};

// Buckets containing rules ported from external upstream linters
Expand Down Expand Up @@ -78,6 +80,7 @@ const BUCKET_TO_DEFAULT_CATEGORY = {
security: "Security",
server: "Server",
"state-and-effects": "State & Effects",
solid: "SolidJS",
"tanstack-query": "TanStack Query",
"tanstack-start": "TanStack Start",
"view-transitions": "Correctness",
Expand Down
1 change: 1 addition & 0 deletions packages/oxlint-plugin-react-doctor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export {
REACT_NATIVE_RULES,
RECOMMENDED_RULES,
RULES,
SOLID_RULES,
TANSTACK_QUERY_RULES,
TANSTACK_START_RULES,
} from "./rules.js";
Expand Down
Loading
Loading