@alexgorbatchev/pi-skill-library 0.1.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/LICENSE +21 -0
- package/README.md +88 -0
- package/package.json +49 -0
- package/skills-library/.gitkeep +0 -0
- package/skills-library/opencode-config/SKILL.md +51 -0
- package/skills-library/react-development/SKILL.md +135 -0
- package/skills-library/react-development/references/oxlint.md +144 -0
- package/skills-library/react-development/references/oxlintrc.json +16 -0
- package/skills-library/react-development/references/reactPolicyPlugin.js +549 -0
- package/skills-library/react-development/references/reactPolicyPlugin.test.ts +152 -0
- package/src/createLibraryReport.ts +42 -0
- package/src/discoverLibrarySkills.ts +365 -0
- package/src/expandLibrarySkill.ts +10 -0
- package/src/groupLibrarySummariesByScope.ts +37 -0
- package/src/index.ts +1 -0
- package/src/parseLibraryCommand.ts +22 -0
- package/src/piSkillLibraryExtension.ts +209 -0
- package/src/renderLibraryReport.ts +32 -0
- package/src/replaceHomeDirectoryWithTilde.ts +19 -0
- package/src/types.ts +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Gorbatchev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @alexgorbatchev/pi-skill-library
|
|
2
|
+
|
|
3
|
+
[pi](https://pi.dev) extension that discovers `skills-library` roots and exposes their skills through `/library:<skill-name>` commands. This extension solves the problem of too many skills. There are skills that you need only occasionally and maybe don't even need them discoverable.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pi install npm:@alexgorbatchev/pi-skill-library
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
This package does **not** register bundled skills through Pi's normal skill loader.
|
|
14
|
+
Instead, it discovers `skills-library` directories, loads the skills from those roots itself, and expands:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
/library:<skill-name>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
into the same `<skill ...>...</skill>` block format Pi uses for built-in `/skill:<name>` expansion.
|
|
21
|
+
|
|
22
|
+
That keeps these skills out of Pi's default skill discovery flow while still making them explicitly invokable.
|
|
23
|
+
|
|
24
|
+
## Library root locations
|
|
25
|
+
|
|
26
|
+
The extension looks for `skills-library` in these places:
|
|
27
|
+
|
|
28
|
+
- `<cwd>/.pi/skills-library`
|
|
29
|
+
- `<cwd>` and ancestor `.agents/skills-library` directories, stopping at the git root (or filesystem root when no git root exists)
|
|
30
|
+
- `~/.pi/agent/cskills-library`
|
|
31
|
+
- `~/.agents/skills-library`
|
|
32
|
+
- package-local `skills-library` directories derived from discovered package skill roots
|
|
33
|
+
- extra paths configured via Pi settings under `@alexgorbatchev/pi-skills-library.paths`
|
|
34
|
+
|
|
35
|
+
## Settings
|
|
36
|
+
|
|
37
|
+
Use a namespaced block in Pi settings:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"@alexgorbatchev/pi-skills-library": {
|
|
42
|
+
"paths": [
|
|
43
|
+
"./skills-library",
|
|
44
|
+
"~/shared/pi-skills-library"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Path resolution follows normal Pi settings behavior:
|
|
51
|
+
|
|
52
|
+
- paths in `~/.pi/agent/settings.json` resolve relative to `~/.pi/agent`
|
|
53
|
+
- paths in `.pi/settings.json` resolve relative to `.pi`
|
|
54
|
+
- absolute paths are supported
|
|
55
|
+
- `~/...` is supported
|
|
56
|
+
|
|
57
|
+
## Directory layout
|
|
58
|
+
|
|
59
|
+
Each library root should contain normal skill directories:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
skills-library/
|
|
63
|
+
├── my-skill/
|
|
64
|
+
│ └── SKILL.md
|
|
65
|
+
└── another-skill/
|
|
66
|
+
├── SKILL.md
|
|
67
|
+
└── references/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Commands
|
|
71
|
+
|
|
72
|
+
Invoke a library skill directly:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
/library:my-skill
|
|
76
|
+
/library:my-skill additional context here
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Discovered library skills are registered as real extension slash commands at startup and reload, so they show up in slash-command autocomplete like other commands.
|
|
80
|
+
|
|
81
|
+
On startup, the extension prints a library-discovery message into the transcript listing each discovered library root and its skills. Home-directory paths are rendered with the `~/` convention.
|
|
82
|
+
|
|
83
|
+
Use the package info command to print the same report again:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
/pi-skill-library
|
|
87
|
+
```
|
|
88
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alexgorbatchev/pi-skill-library",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Pi extension that exposes skills-library roots through /library:<skill-name> commands.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"packageManager": "bun@1.3.10",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"pi-package",
|
|
10
|
+
"pi-extension",
|
|
11
|
+
"skills",
|
|
12
|
+
"skill",
|
|
13
|
+
"library"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"skills-library",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"pi": {
|
|
25
|
+
"extensions": [
|
|
26
|
+
"./src/index.ts"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@mariozechner/pi-coding-agent": "*"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@mariozechner/pi-coding-agent": "0.64.0",
|
|
34
|
+
"@types/node": "24.7.2",
|
|
35
|
+
"@typescript/native-preview": "7.0.0-dev.20260330.1",
|
|
36
|
+
"dprint": "0.53.0",
|
|
37
|
+
"oxlint": "1.56.0",
|
|
38
|
+
"typescript": "6.0.2"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"dev": "bun x pi -e ./src/index.ts",
|
|
42
|
+
"check": "bun run typecheck && bun run lint && bun run format:check && bun run verify:pi-load",
|
|
43
|
+
"typecheck": "tsgo --noEmit -p tsconfig.json",
|
|
44
|
+
"lint": "oxlint --config oxlintrc.json .",
|
|
45
|
+
"format": "dprint fmt",
|
|
46
|
+
"format:check": "dprint check",
|
|
47
|
+
"verify:pi-load": "PI_OFFLINE=1 bun x pi --no-extensions -e ./src/index.ts --list-models > /dev/null 2>&1"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opencode-config
|
|
3
|
+
description: >-
|
|
4
|
+
Set up and configure opencode.jsonc for OpenCode projects. Use when creating a
|
|
5
|
+
new opencode.jsonc configuration file, adding instruction file paths, or
|
|
6
|
+
configuring OpenCode settings for a repository.
|
|
7
|
+
targets:
|
|
8
|
+
- '*'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenCode Config
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Create and configure `opencode.jsonc` in the repository root to customize OpenCode behavior per project.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
1. Create `opencode.jsonc` in the repository root
|
|
20
|
+
2. Add the schema reference for validation and autocompletion
|
|
21
|
+
3. Add instruction file paths to the `instructions` array
|
|
22
|
+
|
|
23
|
+
### Minimal Configuration
|
|
24
|
+
|
|
25
|
+
```jsonc
|
|
26
|
+
{
|
|
27
|
+
"$schema": "https://opencode.ai/config.json",
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### .github Instructions
|
|
32
|
+
|
|
33
|
+
If there is `.github/instructions` folder update config to include `instructions` field, like so:
|
|
34
|
+
|
|
35
|
+
```jsonc
|
|
36
|
+
"instructions": [
|
|
37
|
+
".github/instructions/*.instructions.md",
|
|
38
|
+
],
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### .github Skills
|
|
42
|
+
|
|
43
|
+
If there is `.github/skills` folder update config to include `skills` field, like so:
|
|
44
|
+
|
|
45
|
+
```jsonc
|
|
46
|
+
"skills": {
|
|
47
|
+
"paths": [
|
|
48
|
+
".github/skills",
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
```
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-development
|
|
3
|
+
description: >-
|
|
4
|
+
Build and modify React components, hooks, context providers, and JSX render
|
|
5
|
+
trees. Use when implementing or refactoring React UI code, component APIs,
|
|
6
|
+
render branches, shared primitives, hook-driven state, DOM structure, or test
|
|
7
|
+
ID conventions. Covers the required `data-testid` naming contract and the ban
|
|
8
|
+
on using `createElement` from React in regular application code.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# React Development
|
|
12
|
+
|
|
13
|
+
Use existing React patterns before introducing new ones. Preserve accessibility, composability, and readable JSX.
|
|
14
|
+
|
|
15
|
+
## Workflow
|
|
16
|
+
|
|
17
|
+
1. Inspect the existing component, shared primitives, hooks, and nearby tests before editing.
|
|
18
|
+
2. Reuse an existing component or hook when one already expresses the pattern.
|
|
19
|
+
3. Keep rendering in JSX. Extract helpers or hooks instead of switching to `createElement`.
|
|
20
|
+
4. Apply the test ID contract exactly when a tagged element is needed.
|
|
21
|
+
5. Run the narrowest relevant validation first, then broader lint and test commands.
|
|
22
|
+
|
|
23
|
+
## Non-negotiable rules
|
|
24
|
+
|
|
25
|
+
### 1. Use the test ID contract exactly
|
|
26
|
+
|
|
27
|
+
Apply these rules exactly unless the repository documents a different contract:
|
|
28
|
+
|
|
29
|
+
- Use the plain component name on the root rendered element of a component.
|
|
30
|
+
- Use `ComponentName--thing` for tagged child elements inside that component.
|
|
31
|
+
- Use kebab-case for `thing`.
|
|
32
|
+
- Use semantic targets, not positional names.
|
|
33
|
+
- Use the local helper component name when a helper component renders its own tagged root.
|
|
34
|
+
- Do not invent `--root` or other suffixes on the root unless the repository explicitly requires them.
|
|
35
|
+
|
|
36
|
+
Valid:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
export function PlanChat() {
|
|
40
|
+
return (
|
|
41
|
+
<section data-testid='PlanChat'>
|
|
42
|
+
<div data-testid='PlanChat--thread-viewport' />
|
|
43
|
+
</section>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
function ReasoningPart() {
|
|
50
|
+
return <ToolCallCard testId='ReasoningPart' />;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Invalid:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
<section data-testid='PlanChat--root' />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
<div data-testid='thread-viewport' />
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
function ReasoningPart() {
|
|
66
|
+
return <ToolCallCard testId='PlanChat--reasoning-card' />;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Prefer accessible queries in tests. Add `data-testid` only when the element is not reliably targetable through role, label, text, or stable semantic structure.
|
|
71
|
+
|
|
72
|
+
### 2. Keep regular React code in JSX
|
|
73
|
+
|
|
74
|
+
Do not use `createElement` or `React.createElement` in ordinary application code.
|
|
75
|
+
|
|
76
|
+
Use JSX for:
|
|
77
|
+
|
|
78
|
+
- normal component bodies
|
|
79
|
+
- conditional rendering
|
|
80
|
+
- lists and mapping
|
|
81
|
+
- wrapper composition
|
|
82
|
+
- provider trees
|
|
83
|
+
- tool or widget registries that can be expressed directly in JSX
|
|
84
|
+
|
|
85
|
+
Allow `createElement` only when a specific domain constraint requires it and that requirement is documented explicitly at the use site or in adjacent documentation. Typical exceptions are rare and include cases such as:
|
|
86
|
+
|
|
87
|
+
- schema-driven renderers
|
|
88
|
+
- AST or MDX renderers
|
|
89
|
+
- plugin systems that receive component types dynamically
|
|
90
|
+
- framework integration points that require raw element factory calls
|
|
91
|
+
|
|
92
|
+
Do not introduce `createElement` just to:
|
|
93
|
+
|
|
94
|
+
- avoid JSX syntax
|
|
95
|
+
- build dynamic props more mechanically
|
|
96
|
+
- mimic framework internals
|
|
97
|
+
- shorten code that JSX already expresses clearly
|
|
98
|
+
|
|
99
|
+
When an exception is truly required, isolate it, document why JSX is insufficient, and test it.
|
|
100
|
+
|
|
101
|
+
## Component design rules
|
|
102
|
+
|
|
103
|
+
- Prefer function components and hooks over class components unless the codebase already requires a class boundary.
|
|
104
|
+
- Keep props narrow and typed.
|
|
105
|
+
- Extract pure transforms into helpers instead of embedding large calculations in render.
|
|
106
|
+
- Extract repeated stateful behavior into hooks only when more than one caller needs it or the component becomes hard to read.
|
|
107
|
+
- Reuse shared primitives for buttons, inputs, dialogs, cards, and layout shells before adding one-off markup.
|
|
108
|
+
- Keep render branches explicit. Make loading, empty, error, and success states easy to read.
|
|
109
|
+
- Preserve accessible names and roles when refactoring structure.
|
|
110
|
+
|
|
111
|
+
## Review checklist
|
|
112
|
+
|
|
113
|
+
Before finishing a React change, verify all of the following:
|
|
114
|
+
|
|
115
|
+
- root test IDs use the plain component name
|
|
116
|
+
- child test IDs use `ComponentName--thing`
|
|
117
|
+
- helper components with their own tagged roots use their own names
|
|
118
|
+
- no new `createElement` usage was introduced without an explicit documented exception
|
|
119
|
+
- shared primitives were reused where appropriate
|
|
120
|
+
- accessible queries remain possible for user-facing controls
|
|
121
|
+
- relevant lint, type, and test commands were run
|
|
122
|
+
|
|
123
|
+
## References
|
|
124
|
+
|
|
125
|
+
- Read `references/oxlint.md` when adding or changing React-specific lint rules, custom Oxlint plugins, test ID enforcement, or `createElement` bans.
|
|
126
|
+
- Read `references/reactPolicyPlugin.js` for a concrete local Oxlint plugin example.
|
|
127
|
+
- Read `references/reactPolicyPlugin.test.ts` for a concrete Bun test harness for the plugin.
|
|
128
|
+
- Read `references/oxlintrc.json` for a concrete scoped config example.
|
|
129
|
+
|
|
130
|
+
## Companion skills
|
|
131
|
+
|
|
132
|
+
Use related skills when the task goes deeper in those areas:
|
|
133
|
+
|
|
134
|
+
- `react-testing` for Storybook stories, play functions, and interaction coverage
|
|
135
|
+
- `typescript-code-quality` when TypeScript structure and type-safety rules matter heavily
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Oxlint for React Repositories
|
|
2
|
+
|
|
3
|
+
Read this file when the task involves adding, tightening, or debugging React lint rules, custom Oxlint plugins, or CI enforcement.
|
|
4
|
+
|
|
5
|
+
## Enforcement strategy
|
|
6
|
+
|
|
7
|
+
Use Oxlint for fast editor and CI feedback.
|
|
8
|
+
|
|
9
|
+
Split enforcement into two groups:
|
|
10
|
+
|
|
11
|
+
1. **Built-in rules** for generic quality and correctness
|
|
12
|
+
2. **Local JS plugins** for repository-specific React contracts
|
|
13
|
+
|
|
14
|
+
Prefer built-in rules when they express the requirement directly. Use a local plugin only when the rule is specific to the repository and cannot be expressed well with built-ins.
|
|
15
|
+
|
|
16
|
+
## High-value React policies to enforce
|
|
17
|
+
|
|
18
|
+
### 1. Ban `createElement` in regular application code
|
|
19
|
+
|
|
20
|
+
Use a linter rule or repo-local plugin to reject:
|
|
21
|
+
|
|
22
|
+
- `import { createElement } from 'react'`
|
|
23
|
+
- `React.createElement(...)`
|
|
24
|
+
|
|
25
|
+
Scope exceptions explicitly to:
|
|
26
|
+
|
|
27
|
+
- tests
|
|
28
|
+
- Storybook setup/mocks
|
|
29
|
+
- documented framework boundaries
|
|
30
|
+
- documented schema/plugin renderers
|
|
31
|
+
|
|
32
|
+
If the repository allows a rare production exception, require a short comment at the use site explaining why JSX is insufficient.
|
|
33
|
+
|
|
34
|
+
## 2. Enforce the test ID naming contract
|
|
35
|
+
|
|
36
|
+
If the repository uses test IDs, prefer a custom plugin for exact policy enforcement.
|
|
37
|
+
|
|
38
|
+
Example policy:
|
|
39
|
+
|
|
40
|
+
- component root: `ComponentName`
|
|
41
|
+
- child elements: `ComponentName--thing`
|
|
42
|
+
- helper components with their own tagged roots use their own names
|
|
43
|
+
|
|
44
|
+
Use a local plugin when the policy depends on component names, render branches, or JSX structure.
|
|
45
|
+
|
|
46
|
+
## 3. Scope rules by file type
|
|
47
|
+
|
|
48
|
+
Do not run React-specific rules on the whole repository.
|
|
49
|
+
|
|
50
|
+
Use `overrides` to target the file types the policy actually governs.
|
|
51
|
+
|
|
52
|
+
For repositories where every `.tsx` file is in scope for React UI policy, prefer this broad pattern so new files are not missed:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
57
|
+
"jsPlugins": ["./scripts/oxlint/reactPolicyPlugin.js"],
|
|
58
|
+
"overrides": [
|
|
59
|
+
{
|
|
60
|
+
"files": ["**/*.tsx"],
|
|
61
|
+
"rules": {
|
|
62
|
+
"repo-react/no-regular-create-element": "error",
|
|
63
|
+
"repo-react/require-component-root-testid": "error"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Use narrower globs only when the repository deliberately excludes some `.tsx` categories from the policy.
|
|
71
|
+
|
|
72
|
+
## Local plugin guidance
|
|
73
|
+
|
|
74
|
+
Implement a local plugin when the repository needs React-specific contracts that built-ins do not cover.
|
|
75
|
+
|
|
76
|
+
Concrete reference files in this skill:
|
|
77
|
+
|
|
78
|
+
- `references/reactPolicyPlugin.js` — example plugin with `no-regular-create-element` and `require-component-root-testid`
|
|
79
|
+
- `references/reactPolicyPlugin.test.ts` — Bun tests that run Oxlint against temp fixtures
|
|
80
|
+
- `references/oxlintrc.json` — scoped config example wiring the plugin into Oxlint
|
|
81
|
+
|
|
82
|
+
Typical cases:
|
|
83
|
+
|
|
84
|
+
- test ID naming derived from component names
|
|
85
|
+
- banning `createElement` except in scoped files
|
|
86
|
+
- repository-specific wrapper conventions
|
|
87
|
+
- enforcing root render wrappers for provider-only components
|
|
88
|
+
|
|
89
|
+
Keep plugins small and exact. One repository contract per rule is usually the right granularity.
|
|
90
|
+
|
|
91
|
+
## Rule design guidance
|
|
92
|
+
|
|
93
|
+
### `no-regular-create-element`
|
|
94
|
+
|
|
95
|
+
The rule should:
|
|
96
|
+
|
|
97
|
+
- flag `createElement` imports from `react`
|
|
98
|
+
- flag `React.createElement(...)`
|
|
99
|
+
- ignore test files and documented exception paths through config scoping, not heuristics
|
|
100
|
+
- report a direct message: use JSX instead of `createElement` in regular React code
|
|
101
|
+
|
|
102
|
+
### `require-component-root-testid`
|
|
103
|
+
|
|
104
|
+
The rule should:
|
|
105
|
+
|
|
106
|
+
- detect exported PascalCase components
|
|
107
|
+
- inspect all non-null render branches
|
|
108
|
+
- require exact root test IDs
|
|
109
|
+
- validate child test IDs against the component name
|
|
110
|
+
- ignore nested functions and nested classes while traversing one component body
|
|
111
|
+
|
|
112
|
+
Use a repository-level test in addition to the plugin when the rule performs AST-heavy structural checks.
|
|
113
|
+
|
|
114
|
+
## Validation workflow
|
|
115
|
+
|
|
116
|
+
When adding or changing React lint rules:
|
|
117
|
+
|
|
118
|
+
1. Run the targeted Oxlint command on the affected files first.
|
|
119
|
+
2. Run the plugin tests if a local plugin changed.
|
|
120
|
+
3. Run the type checker.
|
|
121
|
+
4. Run adjacent React tests.
|
|
122
|
+
5. Run the broader repo lint command last.
|
|
123
|
+
|
|
124
|
+
Example:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
bun x oxlint -c oxlintrc.json --deny-warnings src/components
|
|
128
|
+
bun test scripts/oxlint/__tests__/reactPolicyPlugin.test.ts
|
|
129
|
+
bun x tsgo -p . --noEmit
|
|
130
|
+
bun test src/components --max-concurrency=1
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Failure policy
|
|
134
|
+
|
|
135
|
+
Do not weaken a React lint rule just to get a change through.
|
|
136
|
+
|
|
137
|
+
If the rule blocks valid code, fix one of these instead:
|
|
138
|
+
|
|
139
|
+
- the component structure
|
|
140
|
+
- the rule implementation
|
|
141
|
+
- the file scope in config
|
|
142
|
+
- the documented policy
|
|
143
|
+
|
|
144
|
+
Do not add blanket ignores when a scoped override or a better rule is the correct solution.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"jsPlugins": ["./scripts/oxlint/reactPolicyPlugin.js"],
|
|
4
|
+
"rules": {
|
|
5
|
+
"eqeqeq": "error"
|
|
6
|
+
},
|
|
7
|
+
"overrides": [
|
|
8
|
+
{
|
|
9
|
+
"files": ["**/*.tsx"],
|
|
10
|
+
"rules": {
|
|
11
|
+
"repo-react/no-regular-create-element": "error",
|
|
12
|
+
"repo-react/require-component-root-testid": "error"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|