@colrealpro/react-luau-doctor 0.17.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 +127 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/action.yml +71 -0
- package/dist/cli.js +11265 -0
- package/dist/cli.js.map +50 -0
- package/dist/runtime-lock.json +29 -0
- package/docs/analysis.md +37 -0
- package/docs/ci.md +73 -0
- package/docs/cli.md +115 -0
- package/docs/development.md +62 -0
- package/docs/rules.md +56 -0
- package/package.json +57 -0
- package/vendor/tree-sitter-luau.LICENSE +21 -0
- package/vendor/tree-sitter-luau.wasm +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "react-luau-doctor",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"web-tree-sitter": "0.26.11",
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@types/bun": "1.3.14",
|
|
12
|
+
"typescript": "5.8.3",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
"packages": {
|
|
17
|
+
"@types/bun": ["@types/bun@1.3.14", "https://registry.npmjs.org/@types/bun/-/bun-1.3.14.tgz", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
|
18
|
+
|
|
19
|
+
"@types/node": ["@types/node@26.1.1", "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="],
|
|
20
|
+
|
|
21
|
+
"bun-types": ["bun-types@1.3.14", "https://registry.npmjs.org/bun-types/-/bun-types-1.3.14.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
|
22
|
+
|
|
23
|
+
"typescript": ["typescript@5.8.3", "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
|
24
|
+
|
|
25
|
+
"undici-types": ["undici-types@8.3.0", "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
|
|
26
|
+
|
|
27
|
+
"web-tree-sitter": ["web-tree-sitter@0.26.11", "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.26.11.tgz", {}, "sha512-Q5Dm3YTIXSXuH6FxX6RuzX2Qwpc4DPGiYMU87Wg5Z8OIStiQFiUex4zMDc0vBTw78EphaYJacncJghCHzbZptg=="],
|
|
28
|
+
}
|
|
29
|
+
}
|
package/docs/analysis.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# How analysis works
|
|
2
|
+
|
|
3
|
+
Doctor parses source with `web-tree-sitter` and a bundled Luau grammar. It builds a model of React aliases, functions, hooks, state, refs, and component calls before running rules. It never executes the Luau program.
|
|
4
|
+
|
|
5
|
+
## File and project evidence
|
|
6
|
+
|
|
7
|
+
Requires and local aliases identify React and ReactRoblox usage. A namespace does not need to be named `React`. Directory scans filter out modules without React evidence, but supporting modules can still contribute to project analysis.
|
|
8
|
+
|
|
9
|
+
Cross-file resolution compares normalized path segments. Short names are used only when they identify a unique module; longer unique matches take precedence. This avoids confusing `Controller` with `SessionController`, or guessing between two unrelated `Button` modules. Dynamic requires and runtime module selection can remain unresolved.
|
|
10
|
+
|
|
11
|
+
The project model summarizes memoized components, externally updated state hooks, callback wrappers, state/Binding API pairs, and source-visible effects. Effect propagation follows imports and calls to find operations that mutate external state during render. Unknown opaque methods are not automatically assumed to have side effects.
|
|
12
|
+
|
|
13
|
+
## Binding recommendations
|
|
14
|
+
|
|
15
|
+
The Binding rules trace state updated by external callbacks, including signals and frame events. They inspect how consumers read that state before recommending a Binding.
|
|
16
|
+
|
|
17
|
+
A warning can be justified when reads flow into bindable host properties or through a custom component proven to forward them. Mixed structural use and unknown component props can produce a lower-confidence candidate instead. A Binding cannot replace every state value: values controlling child structure or other ordinary Lua decisions may still need React state.
|
|
18
|
+
|
|
19
|
+
Measurement hooks have additional producer-side evidence: a property-change subscription, a read of that property, and a state update. Their recommendations may require a Binding-aware effect or a larger consumer refactor. Dual state/Binding hooks and sibling APIs are inferred from available source, not a configurable list of project hook names.
|
|
20
|
+
|
|
21
|
+
## Syntax compatibility
|
|
22
|
+
|
|
23
|
+
A preprocessing pass adapts certain modern Luau constructs that the grammar does not directly support. It aims to preserve byte offsets and line positions. Remaining parse failures are reported as `react-luau/parse-error`, and other rules stop for that file to avoid cascaded findings.
|
|
24
|
+
|
|
25
|
+
## Confidence and scope limits
|
|
26
|
+
|
|
27
|
+
Static evidence cannot establish all runtime behavior. Dynamic dispatch, metatables, unavailable dependencies, and indirect ownership can lead to missed findings or findings that need human judgment. Test a proposed repair in Roblox and profile performance changes when relevant.
|
|
28
|
+
|
|
29
|
+
Git changed scope compares diagnostic multisets using file, rule, severity, and message. Moving a finding within the same file usually does not make it new. Replacing one finding with another identical finding can cancel out in that comparison.
|
|
30
|
+
|
|
31
|
+
Scoped scans overlay selected file contents on current project context. They do not reconstruct every file from the historical revision. Deleted files are included in baseline accounting, but cross-file changes can still make historical inference imperfect. Use a full scan and review both revisions when investigating a cross-file regression.
|
|
32
|
+
|
|
33
|
+
The health score weights findings by severity and scanned-file count. It is a triage aid, not an estimate of FPS, reliability, or production readiness. Zero findings can also mean that no eligible React files were found; check `scannedFiles` and partial-report fields.
|
|
34
|
+
|
|
35
|
+
## Supported input
|
|
36
|
+
|
|
37
|
+
Doctor targets source-controlled `.lua` and `.luau` files using React-Luau. It does not read Roblox place files, inspect a live Studio session, analyze `.tsx`, or provide DOM, CSS, React Native, or Next.js checks. The npm package is a CLI distribution; a public programmatic API is not supported.
|
package/docs/ci.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# CI setup
|
|
2
|
+
|
|
3
|
+
There are two workflows to distinguish: this repository's own build/test CI, and the analyzer workflow installed into your Roblox repository.
|
|
4
|
+
|
|
5
|
+
## Install into a Roblox repository
|
|
6
|
+
|
|
7
|
+
Build and link Doctor as described in the [README](../README.md). From the Roblox repository, run:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
react-luau-doctor ci install --yes
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Commit both `.github/workflows/react-luau-doctor.yml` and the entire `.github/actions/react-luau-doctor` directory. The latter includes the bundled CLI, grammar, license notices, package metadata, and lockfile. This copy pins the analyzer to the installed version without requiring Doctor on npm. CI still needs network access to install Bun and the locked parser dependency.
|
|
14
|
+
|
|
15
|
+
The workflow checks out full Git history. Pull requests use `changed` scope by default. Pushes to `main` run a full advisory scan. Change the branch trigger if your default branch has another name.
|
|
16
|
+
|
|
17
|
+
## Gates and reporting
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
react-luau-doctor ci config --blocking error --scope changed --yes
|
|
21
|
+
react-luau-doctor ci config --no-comment --no-review-comments --no-commit-status --yes
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The default gate is `none`. `error` fails a PR check for errors; `warning` fails for warnings or errors. Push scans remain advisory regardless of this setting.
|
|
25
|
+
|
|
26
|
+
The generated workflow requests `contents: read`, `pull-requests: write`, `issues: write`, and `statuses: write`. Reporting can create or update a summary, replace up to 20 inline comments per run, and publish a commit status. Only bot-authored comments carrying Doctor's markers are managed. Summary details are capped; the workflow log contains the report.
|
|
27
|
+
|
|
28
|
+
Inline comments use primary diagnostic lines present in the diff. A finding included through a secondary evidence highlight can appear in the report without an inline comment. Fixed-issue counts include findings removed by deleting files and respect project selection and configuration.
|
|
29
|
+
|
|
30
|
+
Fork PR tokens commonly lack write permissions. Reporting failures are logged while scan results, outputs, and the configured gate remain available. Disabling reporting avoids those API calls. Keep the `pull_request` trigger; do not switch to `pull_request_target` to obtain write access while executing PR-controlled files.
|
|
31
|
+
|
|
32
|
+
## Upgrade
|
|
33
|
+
|
|
34
|
+
After updating and rebuilding your Doctor installation:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
react-luau-doctor ci upgrade --yes
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This refreshes the copied runtime and wrapper while preserving supported workflow settings. Review and commit all generated changes. `ci config` also refreshes the runtime from the invoking installation. These commands regenerate managed files; keep custom workflow logic in a separate workflow.
|
|
41
|
+
|
|
42
|
+
`ci install` and `ci upgrade` accept `--pr`, which uses authenticated GitHub CLI access to create a branch, commit generated files, push, and open a PR. Omit it when you want to review the files locally first.
|
|
43
|
+
|
|
44
|
+
## Direct repository Action
|
|
45
|
+
|
|
46
|
+
After publishing this repository, you can reference its root `action.yml` instead of committing a runtime copy. Select an existing commit or release tag from `colrealpro/react-luau-doctor`; no release tag is assumed to exist yet. Pinning a full commit SHA also pins `dist/cli.js`.
|
|
47
|
+
|
|
48
|
+
Your workflow must check out the target repository with `fetch-depth: 0`, set the required permissions, then call the Action. Inputs are `directory`, `project`, `scope`, `blocking`, `comment`, `review-comments`, and `commit-status`. Input values pass through environment variables before shell invocation.
|
|
49
|
+
|
|
50
|
+
## Outputs
|
|
51
|
+
|
|
52
|
+
| Output | Meaning |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `score` | Heuristic score for the reported findings. |
|
|
55
|
+
| `total-issues` | Number of reported diagnostics. |
|
|
56
|
+
| `fixed-issues` | Baseline findings removed by a PR. |
|
|
57
|
+
| `error-count` | Reported errors. |
|
|
58
|
+
| `warning-count` | Reported warnings. |
|
|
59
|
+
| `affected-files` | Files with reported findings. |
|
|
60
|
+
|
|
61
|
+
## GitLab
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
react-luau-doctor ci install --provider gitlab --blocking error --yes
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Commit `.gitlab-ci.yml` and `.gitlab/react-luau-doctor`. The generated job installs the copied runtime's parser dependency and runs a CLI gate in a pinned Bun image. It does not publish merge-request comments or statuses. Full Git history is requested; explicitly adapt the comparison base to your merge-request workflow if needed. Existing unrelated `.gitlab-ci.yml` files are not overwritten.
|
|
68
|
+
|
|
69
|
+
## Verification
|
|
70
|
+
|
|
71
|
+
The test suite simulates GitHub API requests for summary creation and updates, review replacement, commit statuses, and forbidden responses. It also checks copied-runtime execution and shell input handling. This repository's CI runs the root composite Action against an example with API reporting disabled.
|
|
72
|
+
|
|
73
|
+
Before enabling a required check, run real PRs in your repository that introduce an error, repair it, delete an affected component, and originate from a fork. Confirm the gate, outputs, comments, and status behavior. Local simulation does not validate GitHub account permissions or hosted runner execution.
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# CLI and configuration
|
|
2
|
+
|
|
3
|
+
Examples assume you built the source checkout and ran `bun link`. You can also invoke its absolute `dist/cli.js` path with Bun from the directory you want to analyze.
|
|
4
|
+
|
|
5
|
+
## Scan targets
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
react-luau-doctor .
|
|
9
|
+
react-luau-doctor src/interface --verbose
|
|
10
|
+
react-luau-doctor src/interface/Label.luau
|
|
11
|
+
react-luau-doctor . --project client,shared
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Directory discovery selects `.lua` and `.luau` files with React or ReactRoblox evidence. Explicit file targets are always analyzed and bypass directory include/ignore filters. Dependency and output directories such as `node_modules`, `Packages`, `DevPackages`, `ServerPackages`, `vendor`, `build`, `dist`, and `.git` are skipped during discovery.
|
|
15
|
+
|
|
16
|
+
Local subdirectory scans use the configuration in the command's working directory, with paths reported relative to that directory. Run from the project root for consistent paths.
|
|
17
|
+
|
|
18
|
+
## Git scopes
|
|
19
|
+
|
|
20
|
+
| Scope | Result |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `full` | Findings across the selected target. No Git repository required. |
|
|
23
|
+
| `files` | All findings in changed files. |
|
|
24
|
+
| `changed` | Findings in changed files that were not present in the baseline. |
|
|
25
|
+
| `lines` | Findings whose primary span or evidence highlights overlap changed lines. |
|
|
26
|
+
|
|
27
|
+
Pass `--base main` or a commit to choose an explicit comparison. Use `--include-untracked` to include new untracked files, or `--changed-files-from paths.txt` for a newline-separated path list. Git scopes respect configured include/ignore patterns.
|
|
28
|
+
|
|
29
|
+
`--staged` checks Git index content. It uses file scope unless line scope is requested. Project context includes other source files on disk; this is not an isolated checkout of the complete index or baseline. See [analysis limits](analysis.md).
|
|
30
|
+
|
|
31
|
+
## Output and exit codes
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
react-luau-doctor . --verbose
|
|
35
|
+
react-luau-doctor . --json --json-compact
|
|
36
|
+
react-luau-doctor . --json-out doctor-report.json
|
|
37
|
+
react-luau-doctor . --output-dir .doctor
|
|
38
|
+
react-luau-doctor . --blocking warning
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Local scans default to `--blocking error`. The default display summarizes findings. `--verbose` adds per-file details and help. `--output-dir` writes `report.json`, `diagnostics.json`, and `summary.json`.
|
|
42
|
+
|
|
43
|
+
JSON schema version 1 includes the root, scanned file count, duration, score, severity counts, and diagnostics. Each diagnostic has an ID, rule, category, severity, message, file, and location. Help, evidence highlights, and suggested-change previews may also be present. IDs include source offsets, so moving code can change an ID.
|
|
44
|
+
|
|
45
|
+
`--blocking none` is advisory, `error` fails for errors, and `warning` fails for warnings or errors. Findings that pass the gate return 0; a failed gate or command error returns nonzero. Suggestions do not independently fail a gate. Filters affect reported findings and therefore the gate.
|
|
46
|
+
|
|
47
|
+
Use `--category Hooks`, repeatable for multiple categories, or `--min-severity warning` to narrow results. `--no-warnings` selects errors only. `--no-score` hides the score and `--no-color` disables ANSI colors.
|
|
48
|
+
|
|
49
|
+
`--max-duration 10` requests a shared scan budget in seconds. Budget exhaustion returns a partial report with skipped files; individual analysis operations can exceed the deadline before the next checkpoint. Do not treat a partial report as a complete audit.
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Doctor reads `react-luau-doctor.config.json`, falling back to `doctor.config.json`. It does not search ancestor directories for local scan configuration.
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"include": ["src/**/*.luau", "shared/**/*.lua"],
|
|
58
|
+
"ignore": ["src/generated/**"],
|
|
59
|
+
"respectInlineDisables": true,
|
|
60
|
+
"rules": {
|
|
61
|
+
"react-luau/exhaustive-deps": "error",
|
|
62
|
+
"react-luau/no-array-index-as-key": "off"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
A rule setting is `error`, `warning`, `suggestion`, or `off`. An explicit severity applies to every finding from that rule, including findings normally downgraded for uncertainty. Without an override, individual findings may have lower severity than the rule default. Unknown rule IDs produce an error. In version 0.17.0, Instance creation and tween render checks share `react-luau/no-side-effects-in-render`; replace their former separate rule settings and suppression names with that shared ID.
|
|
68
|
+
|
|
69
|
+
Patterns support `*`, `**`, and `?`; they are not full gitignore syntax. `**/` can match zero directories. Paths are relative to the scan project root.
|
|
70
|
+
|
|
71
|
+
You can edit rule policy through the CLI:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
react-luau-doctor rules set react-luau/exhaustive-deps error
|
|
75
|
+
react-luau-doctor rules disable react-luau/no-array-index-as-key
|
|
76
|
+
react-luau-doctor rules list --configured --json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Suppressions
|
|
80
|
+
|
|
81
|
+
```luau
|
|
82
|
+
-- react-luau-doctor-disable-next-line no-prop-mutation
|
|
83
|
+
props.value = "legacy"
|
|
84
|
+
|
|
85
|
+
-- react-luau-doctor-disable no-array-index-as-key
|
|
86
|
+
-- intentional code here
|
|
87
|
+
-- react-luau-doctor-enable no-array-index-as-key
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Bare rule names and names prefixed with `react-luau/` are accepted. Prefer a next-line suppression and add a comment explaining the exception. `--no-respect-inline-disables` includes suppressed findings during an audit.
|
|
91
|
+
|
|
92
|
+
## Explain a finding
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
react-luau-doctor why src/Label.luau:12
|
|
96
|
+
react-luau-doctor rules explain react-luau/exhaustive-deps
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`rules explain` accepts a full rule ID or a short name such as `exhaustive-deps`. It shows what the rule checks, current and suggested code, and repair notes. Add `--json` to receive the same example as `example.before`, `example.after`, `example.note`, and `example.kind`. Examples describe a pattern; they are not edits inferred from your project.
|
|
100
|
+
|
|
101
|
+
`why` rescans with project context and shows matching findings, code frames, rule intent, confidence, repair guidance, and available previews. Review example-pattern previews before applying them.
|
|
102
|
+
|
|
103
|
+
## Cache
|
|
104
|
+
|
|
105
|
+
Doctor stores an incremental cache outside the scanned repository:
|
|
106
|
+
|
|
107
|
+
| Platform | Default location |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| Linux | `$XDG_CACHE_HOME/react-luau-doctor`, otherwise `~/.cache/react-luau-doctor` |
|
|
110
|
+
| macOS | `~/Library/Caches/react-luau-doctor` |
|
|
111
|
+
| Windows | `%LOCALAPPDATA%/react-luau-doctor/Cache` |
|
|
112
|
+
|
|
113
|
+
Set `REACT_LUAU_DOCTOR_CACHE_DIR` to choose a location. Use `--no-cache` or `REACT_LUAU_DOCTOR_DISABLE_CACHE=1` to bypass it. Cache entries can include source-derived information, so treat the directory as local project data.
|
|
114
|
+
|
|
115
|
+
For the complete option list, run `react-luau-doctor --help`. Compatibility flags for dead-code and supply-chain checks do not implement those analyses.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Development and releases
|
|
2
|
+
|
|
3
|
+
Use Bun 1.3.14 for reproducible release builds. Newer Bun versions can run the CLI, but bundle output can vary with the builder version. Git is required by the scoped-scan tests. Package verification needs `tar` and registry access. It uses npm when available, otherwise runs npm through Bun.
|
|
4
|
+
|
|
5
|
+
## Work locally
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun install --frozen-lockfile
|
|
9
|
+
bun run build
|
|
10
|
+
bun run check
|
|
11
|
+
bun test
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Build before testing because the CI installer copies the bundled runtime into temporary test repositories. `bun test` runs fixture-based rules, Git scope cases, configuration tests, CLI subprocesses, and simulated GitHub API reporting. The API tests bind only to loopback and use a test token.
|
|
15
|
+
|
|
16
|
+
Only `node_modules/` is ignored. Keep `dist/`, `vendor/`, and both lockfiles tracked; the GitHub Action runs the committed bundle directly.
|
|
17
|
+
|
|
18
|
+
## Source layout
|
|
19
|
+
|
|
20
|
+
| Path | Responsibility |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `src/cli.ts` | Commands, options, explanation output, exit gates. |
|
|
23
|
+
| `src/scanner.ts` | File scans, rule execution, diagnostic construction. |
|
|
24
|
+
| `src/ast/` | Syntax traversal and file-level React evidence. |
|
|
25
|
+
| `src/project-model.ts` | Cross-file React relationships. |
|
|
26
|
+
| `src/project-effects.ts` | Source-visible effects and propagation. |
|
|
27
|
+
| `src/rules/` | Rule definitions and repair guidance. |
|
|
28
|
+
| `src/git.ts`, `src/scope.ts` | Git content selection and comparisons. |
|
|
29
|
+
| `src/ci.ts` | Generated workflows, runtime copying, GitHub reporting. |
|
|
30
|
+
| `vendor/` | Luau parser grammar and its license. |
|
|
31
|
+
|
|
32
|
+
The build bundles `src/cli.ts` into `dist/cli.js`, leaving runtime dependencies external. Commit all `dist` files because the root GitHub Action runs them directly. The parser locates its grammar relative to the bundle; preserve the package directory structure when copying it.
|
|
33
|
+
|
|
34
|
+
## Change a rule
|
|
35
|
+
|
|
36
|
+
Add a minimal failing fixture and a valid counterpart. Test the intended diagnostic, location, default severity, and help. Cover explicit severity overrides when a rule supplies confidence-based severities. Register new rules in `src/rules/index.ts`, add a before/after repair example in `src/fix-examples.ts`, and update the catalog in `docs/rules.md`. Tests require an example for every rule and parse each suggested snippet.
|
|
37
|
+
|
|
38
|
+
Check a proposed repair in Roblox where runtime behavior matters. Tests of syntax alone cannot validate UI behavior or performance.
|
|
39
|
+
|
|
40
|
+
## Change CI
|
|
41
|
+
|
|
42
|
+
Keep root `action.yml` synchronized with `renderPublishedGitHubAction()` in `src/ci.ts`. The test suite checks exact equality. Pass variable Action inputs through environment variables; do not interpolate them directly into shell source.
|
|
43
|
+
|
|
44
|
+
Generated CI copies runtime files from the installed package, restoring `bun.lock` from the packaged `dist/runtime-lock.json` when needed. npm excludes the original lockfile. The copied `package.json` records the analyzer version. Do not make an installer depend on an npm release that does not exist.
|
|
45
|
+
|
|
46
|
+
Repository CI typechecks, tests, executes the local composite Action against a fixture, verifies package contents, and compares rebuilt `dist` with committed output. Hosted Actions execution remains a separate check from local API simulation.
|
|
47
|
+
|
|
48
|
+
## Release checklist
|
|
49
|
+
|
|
50
|
+
1. Update `package.json` and `package-lock.json` versions together. A version change also invalidates persistent analysis caches.
|
|
51
|
+
2. Build with Bun 1.3.14, run typechecking and the full tests, and verify the root Action template.
|
|
52
|
+
3. Run `bun run verify:package` to pack, inspect, install, scan, and generate CI from an isolated tarball. You can also run `npm pack --dry-run` to inspect the package list. It must include the bundle, grammar, lockfile, license notices, and docs. It must exclude tests, dependencies, and removed features.
|
|
53
|
+
4. Install the actual tarball in a temporary project and run the CLI and `ci install`. This checks distribution paths separately from source tests.
|
|
54
|
+
5. Commit source, documentation, and rebuilt `dist`. Push to `colrealpro/react-luau-doctor` and wait for GitHub CI.
|
|
55
|
+
6. Test real PR reporting and a fork PR in a disposable repository before recommending required checks.
|
|
56
|
+
7. Create a release tag only after the checks pass. If publishing npm, publish the verified version and then change the README's installation status and examples.
|
|
57
|
+
|
|
58
|
+
Publishing npm is optional for source installation and the GitHub Action. npm distributes the developer CLI; it does not install a runtime library into Roblox. This checkout does not publish packages, create releases, or push changes automatically.
|
|
59
|
+
|
|
60
|
+
## Report a problem
|
|
61
|
+
|
|
62
|
+
Include the tool version, Bun version, operating system, minimal Luau source, configuration, and the command you ran. For Git-related issues, describe the base revision and whether edits were staged. Remove private source and tokens from shared reports.
|
package/docs/rules.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Rule catalog
|
|
2
|
+
|
|
3
|
+
Doctor currently includes 35 rules. This table lists their default severities; individual findings can be downgraded when evidence is uncertain. Explicit configuration overrides the severity for every finding from that rule.
|
|
4
|
+
|
|
5
|
+
| Rule | Default | Category | Checks |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| `react-luau/parse-error` | error | Correctness | Report executable Luau syntax that the bundled parser cannot form into a complete syntax tree. |
|
|
8
|
+
| `react-luau/rules-of-hooks` | error | Hooks | Hooks must run in the same order on every render of a React component or custom hook. |
|
|
9
|
+
| `react-luau/exhaustive-deps` | warning | Hooks | React hook dependency tables should include captured reactive render values. |
|
|
10
|
+
| `react-luau/effect-needs-cleanup` | warning | Effects | Effects that create owned resources or outliving tasks should return matching cleanup. |
|
|
11
|
+
| `react-luau/no-derived-state-effect` | warning | Effects | Avoid copying render-known derived values into state from an effect. |
|
|
12
|
+
| `react-luau/no-self-updating-effect` | warning | Effects | Effects should not unconditionally update state that is also one of their dependencies. |
|
|
13
|
+
| `react-luau/no-effect-with-fresh-deps` | error | Hooks | Dependency tables should not contain tables or functions recreated on every render. |
|
|
14
|
+
| `react-luau/no-mutable-in-deps` | error | Hooks | Mutable ref.current values do not belong in hook dependency tables. |
|
|
15
|
+
| `react-luau/prefer-binding-over-state` | warning | Performance | Prefer React.useBinding when externally updated values do not need React reconciliation on every change. |
|
|
16
|
+
| `react-luau/prefer-binding-over-state-candidate` | suggestion | Performance | Surface lower-confidence state-to-Binding opportunities that need developer review. |
|
|
17
|
+
| `react-luau/rerender-unstable-memo-props` | warning | Performance | Warn when fresh table or function props defeat shallow React.memo comparisons. |
|
|
18
|
+
| `react-luau/rerender-high-frequency-state` | warning | Performance | Find state updates from frame callbacks that can rerender expensive component trees continuously. |
|
|
19
|
+
| `react-luau/rerender-unnecessary-usememo` | warning | Performance | Find trivial derived values that cost more to memoize than to compute directly. |
|
|
20
|
+
| `react-luau/rerender-unnecessary-usecallback` | warning | Performance | Find useCallback values whose stable function identity is never observed. |
|
|
21
|
+
| `react-luau/rerender-static-discovery-in-render` | warning | Performance | Find static Instance/module discovery repeated during component render. |
|
|
22
|
+
| `react-luau/rerender-repeated-collection-scan` | warning | Performance | Find repeated direct render passes over the same collection expression. |
|
|
23
|
+
| `react-luau/rerender-static-state` | warning | Performance | Find React state whose setter is never used and therefore cannot change. |
|
|
24
|
+
| `react-luau/prefer-use-ref-for-mutable-cell` | suggestion | Hooks | Prefer useRef over useMemo-created tables that only emulate a mutable current cell. |
|
|
25
|
+
| `react-luau/rerender-functional-setstate` | warning | Performance | Use the functional state setter form when deferred callbacks update from the previous state value. |
|
|
26
|
+
| `react-luau/rerender-lazy-state-init` | warning | Performance | Expensive useState initializers should use React's lazy initializer form. |
|
|
27
|
+
| `react-luau/rerender-lazy-ref-init` | warning | Performance | Avoid eagerly rebuilding expensive values passed to useRef on every render. |
|
|
28
|
+
| `react-luau/rerender-state-only-in-handlers` | warning | Performance | State that is only read from callbacks may be mutable data rather than rendered state. |
|
|
29
|
+
| `react-luau/no-set-state-in-render` | warning | Correctness | Do not call a component's state setter unconditionally during render. |
|
|
30
|
+
| `react-luau/no-direct-state-mutation` | warning | Correctness | Do not mutate table state in place. |
|
|
31
|
+
| `react-luau/no-ref-current-in-render` | warning | Correctness | Avoid mutating ref.current during render except for predictable initialization or deliberate latest-value mirrors. |
|
|
32
|
+
| `react-luau/no-create-context-in-render` | error | Correctness | React contexts must have stable identity and should not be created during render. |
|
|
33
|
+
| `react-luau/no-nested-component-definition` | warning | Architecture | Do not define rendered component types inside another component. |
|
|
34
|
+
| `react-luau/no-random-key` | error | Correctness | React child keys must not be regenerated on each render. |
|
|
35
|
+
| `react-luau/no-yield-in-render` | error | Correctness | React render functions must not yield. |
|
|
36
|
+
| `react-luau/no-task-spawn-in-render` | error | Correctness | Do not schedule asynchronous work during render. |
|
|
37
|
+
| `react-luau/no-side-effects-in-render` | error | Correctness | Do not create Instances, start tweens, subscribe, or perform other externally observable side effects during component render. |
|
|
38
|
+
| `react-luau/no-create-root-in-render` | error | Roblox | Do not create ReactRoblox roots during component render. |
|
|
39
|
+
| `react-luau/no-prop-mutation` | error | Correctness | Component props should be treated as immutable inputs. |
|
|
40
|
+
| `react-luau/no-array-index-as-key` | suggestion | Correctness | Review dynamic React children that use their current array position as identity. |
|
|
41
|
+
| `react-luau/unstable-context-value` | warning | Performance | Avoid recreating context value tables on every provider render when identity matters. |
|
|
42
|
+
|
|
43
|
+
## Investigate and configure
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
react-luau-doctor rules list
|
|
47
|
+
react-luau-doctor rules explain react-luau/exhaustive-deps
|
|
48
|
+
react-luau-doctor why src/Label.luau:12
|
|
49
|
+
react-luau-doctor rules set react-luau/exhaustive-deps error
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Errors, warnings, and suggestions express reporting policy, not proof of a runtime bug. Review the explanation and code context before changing behavior. Suppress intentional exceptions narrowly.
|
|
53
|
+
|
|
54
|
+
The Binding candidate rule is suggestion-tier because the consumer may require ordinary state or a larger refactor. Array-index keys can also be intentional for collections with stable ordering. See [analysis limits](analysis.md) and [configuration](cli.md).
|
|
55
|
+
|
|
56
|
+
Instance creation and tween operations during render are reported by `react-luau/no-side-effects-in-render`, with its severity and configuration. They do not have separate rule IDs or a lazy-ref severity exception.
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@colrealpro/react-luau-doctor",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.17.0",
|
|
7
|
+
"description": "A syntax-aware React-Luau code doctor inspired by React Doctor.",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"react-luau-doctor": "dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"vendor",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"THIRD_PARTY_NOTICES.md",
|
|
19
|
+
"docs",
|
|
20
|
+
"action.yml"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun run scripts/build.ts",
|
|
24
|
+
"check": "bunx tsc -p tsconfig.json --noEmit",
|
|
25
|
+
"test": "bun run build && bun test",
|
|
26
|
+
"doctor:example": "bun run src/cli.ts examples",
|
|
27
|
+
"prepack": "bun run build && bun run check",
|
|
28
|
+
"ci": "bun run build && bun run check && bun test && bun run scripts/verify-package.ts",
|
|
29
|
+
"verify:package": "bun run build && bun run scripts/verify-package.ts"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"bun": ">=1.3.14"
|
|
33
|
+
},
|
|
34
|
+
"packageManager": "bun@1.3.14",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"web-tree-sitter": "0.26.11"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/bun": "1.3.14",
|
|
40
|
+
"typescript": "5.8.3"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"roblox",
|
|
44
|
+
"react-luau",
|
|
45
|
+
"luau",
|
|
46
|
+
"linter",
|
|
47
|
+
"static-analysis"
|
|
48
|
+
],
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/colrealpro/react-luau-doctor.git"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://github.com/colrealpro/react-luau-doctor#readme",
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/colrealpro/react-luau-doctor/issues"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Amaan Qureshi <amaanq12@gmail.com>
|
|
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.
|
|
Binary file
|