You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .agents/skills/migrate-oxfmt/SKILL.md
+43-17Lines changed: 43 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,6 +13,12 @@ An automated migration tool is built into oxfmt, supporting both Prettier and Bi
13
13
14
14
## Step 1: Run Automated Migration
15
15
16
+
First, decide whether the automated tool fits:
17
+
18
+
-**Static root config** (JSON/YAML, or a JS/TS config that just exports a plain object): use `--migrate` below.
19
+
-**Dynamic JS/TS config** (logic such as environment branches or computed values): `--migrate` writes only a resolved snapshot of the values — the logic does not survive. Migrate manually instead, porting the logic to `oxfmt.config.ts` with the option mappings in this guide.
20
+
-**Nested per-directory configs**: `--migrate` only handles the config found from the current directory. Migrate the nested ones manually (see "Nested Config" in Step 2).
21
+
16
22
### From Prettier
17
23
18
24
```bash
@@ -25,6 +31,7 @@ This will:
25
31
- Create `.oxfmtrc.json` with migrated options
26
32
- Migrate `.prettierignore` patterns to `ignorePatterns`
27
33
- Migrate `prettier-plugin-tailwindcss` options to `sortTailwindcss`
- For `formatter.*` options in the table, a `javascript.formatter.*` value of the same name takes precedence when present. `bracketSameLine` is read only from `javascript.formatter.bracketSameLine`.
70
+
- Options not set in `biome.json` are written to `.oxfmtrc.json` with Biome's default values explicitly (e.g. `printWidth: 80`, `useTabs: true`), so the output preserves Biome's formatting behavior.
71
+
60
72
Notes (both sources):
61
73
62
-
- Fails if `.oxfmtrc.json` already exists. Delete it first if you want to re-run.
74
+
- Fails if `.oxfmtrc.json`or `.oxfmtrc.jsonc`already exists. Delete it first if you want to re-run.
63
75
- If no source config is found, creates a blank `.oxfmtrc.json` instead.
64
-
-`overrides` cannot be auto-migrated for either source and must be converted manually.
76
+
-`overrides` cannot be auto-migrated for either source and must be converted manually (a warning is printed if detected).
65
77
66
78
## Step 2: Review Generated Config
67
79
@@ -75,11 +87,15 @@ Prettier and Biome default is 80, oxfmt default is 100. The migration tool sets
75
87
76
88
These Prettier options are skipped during migration:
|`endOfLine: "auto"`| Not supported. Use `"lf"` or `"crlf"` explicitly |
93
+
|`experimentalTernaries`| Not supported in JS/TS files yet |
94
+
|`experimentalOperatorPosition`| Not supported in JS/TS files yet |
95
+
|`requirePragma`, `insertPragma`| Not supported |
96
+
|`parser`, `filepath`| Not applicable to oxfmt |
97
+
98
+
Regex values (e.g. `"/^my-/"`) in `tailwindFunctions` / `tailwindAttributes` are also skipped with a warning — oxfmt only supports literal strings there.
83
99
84
100
### sortPackageJson (Prettier only)
85
101
@@ -100,20 +116,25 @@ The `overrides` field cannot be auto-migrated from either Prettier or Biome. Con
100
116
"overrides": [
101
117
{
102
118
"files": ["*.md"],
119
+
"excludeFiles": ["CHANGELOG.md"],
103
120
"options": { "tabWidth": 4 }
104
121
}
105
122
]
106
123
}
107
124
```
108
125
126
+
(`excludeFiles` is optional.)
127
+
109
128
### Nested Config
110
129
111
-
Oxfmt does not support nested configuration files (e.g., a separate `.oxfmtrc.json` in a subdirectory). If your project used per-directory Prettier or Biome configs, consolidate them using `overrides` with file glob patterns, or run oxfmt separately per directory with different working directories.
130
+
Oxfmt supports nested configuration files: a `.oxfmtrc.json` in a subdirectory applies to files under that directory. Pass `--disable-nested-config` to opt out and use only the root config.
131
+
132
+
However, `--migrate` only migrates the config found from the current directory — it does not walk subdirectories. If the project has per-directory Prettier or Biome configs, you must migrate each one yourself: convert each nested config to a `.oxfmtrc.json` in the same directory manually (using the option mappings in this guide).
112
133
113
134
### Prettier-Compatible Options
114
135
115
136
These options transfer directly with the same behavior:
- JS/TS, JSON/JSONC/JSON5, CSS/SCSS/Less, GraphQL: Formatted natively by oxfmt
187
212
- TOML: Formatted natively (via taplo)
188
-
-CSS, HTML, YAML, Markdown, GraphQL, etc.: Delegated to Prettier internally (when using `npx oxfmt`)
213
+
- HTML, YAML, Markdown, Vue, Svelte, etc.: Delegated to Prettier internally (when using `npx oxfmt`)
189
214
190
215
## Tips
191
216
192
-
- EditorConfig: Oxfmt reads `.editorconfig` automatically for `useTabs`, `tabWidth`, `endOfLine`, `insertFinalNewline`, and `printWidth`. Options in `.oxfmtrc.json` take precedence.
217
+
- Config file: `.oxfmtrc.jsonc` and `oxfmt.config.ts` are also supported as auto-discovered config file names, in addition to `.oxfmtrc.json`. `--migrate` and `--init` only generate `.oxfmtrc.json`; keep it as-is unless the user explicitly asks for another format or the source config had logic to preserve (see Step 1).
218
+
- EditorConfig: Oxfmt reads `.editorconfig` automatically for `useTabs`, `tabWidth`, `endOfLine`, `insertFinalNewline`, `printWidth`, and `singleQuote`. Options in `.oxfmtrc.json` take precedence.
193
219
- CI: Use `npx oxfmt@latest --check` to enforce formatting in CI.
194
220
- LSP: Run `oxfmt --lsp` for editor integration via Language Server Protocol.
195
221
- Schema support: Add `"$schema": "./node_modules/oxfmt/configuration_schema.json"` to `.oxfmtrc.json` for editor autocompletion.
description: Tips for writing performant Oxc linter rules. Use only when editing Rust rule implementations under crates/oxc_linter/src/rules/.
3
+
description: Performance review guidance for Oxc linter rule implementations. Use only when reviewing Rust rule code under crates/oxc_linter/src/rules/ or when explicitly auditing those rules for performance improvements.
4
4
---
5
5
6
-
This skill gives performance guidance for Oxc linter rule implementations.
7
-
8
-
## Scope
9
-
10
-
Use this skill **only** for Rust code under `crates/oxc_linter/src/rules/`.
11
-
12
-
Do not use this skill for linter infrastructure, parser code, semantic analysis, formatter code, tests outside the rules directory, or unrelated crates.
13
-
14
6
## Performance Guidelines
15
7
16
8
### Prefer top-level node kind checks
17
9
18
-
Put node kind checks at the top level of the rule when possible. Rule runner implementations generated by lintgen can recognize implemented node types, which helps avoid invoking rules on unrelated AST nodes.
10
+
Put node kind checks at the rule entry point. If a rule only handles a few syntactic forms, start `run` with an `AstKind` match and return for all other nodes, even when a helper filters again internally. This lets lintgen derive narrower `NODE_TYPES` and avoids dispatching the rule on unrelated AST nodes.
11
+
12
+
After changing the relevant node kinds for a rule, regenerate the rule runner with `cargo lintgen` and consider adding or updating `assert_rule_runs_on_node_types` coverage in `crates/oxc_linter/src/rule.rs`.
13
+
14
+
Implement only the needed entry point. If a rule is a whole-file pass over semantic indexes, use `run_once` by itself. Implementing both `run` and `run_once` prevents useful node-type narrowing.
19
15
20
16
### Do cheaper checks first
21
17
22
-
Order checks from cheapest and most selective to most expensive. Simple equality checks, early returns, and fast paths such as ASCII-only checks should come before semantic lookups, allocations, or deeper AST traversal.
18
+
Order checks from cheapest and most selective to most expensive. Return quickly for common non-matches before doing semantic lookups, allocations, or deeper traversal.
23
19
24
-
Most rules trigger on only a small set of nodes, so quickly return for the common non-matching cases.
20
+
- Matching a small fixed string set with `matches!` before semantic checks.
21
+
- Rejecting lowercase identifiers before global-object checks when only constructors can match.
22
+
- Checking whether a JSX attribute starts with `aria-` before lowercasing it.
23
+
- Checking for required syntax such as a `key` prop before looking up callback parameter symbols.
24
+
- Checking `source_range(span).contains("this")` before running a visitor that only finds `this`.
25
25
26
-
### Optimize for success
26
+
### Delay expensive context
27
27
28
-
Most files do not contain lint errors. Avoid preparing diagnostics, labels, help text, fix data, or other extra context until the rule knows it needs to report an issue.
28
+
Most files do not contain lint errors. Do not prepare diagnostics, labels, help text, fix data, ancestors, symbols, JSX element types, or replacement strings until the rule has found a syntactic candidate that could actually report.
29
29
30
30
### Iterate over the smallest set possible
31
31
32
-
Avoid walking more syntax than necessary.
33
-
34
32
- Use `run_once` when the rule only needs a whole-file pass and does not need to run on every node.
35
33
- Iterate over symbols instead of AST nodes when looking for references to specific names.
36
34
- Prefer targeted lists or semantic data over broad AST traversal when available.
35
+
- For name-based binding checks, use `ctx.scoping().get_binding(scope_id, name)` instead of scanning every binding in `get_bindings(scope_id)`.
36
+
- For global or unresolved identifier checks, start from `ctx.scoping().root_unresolved_references().get(name)` for the small set of relevant names instead of visiting every `IdentifierReference`.
37
+
- When iterating unresolved references, still verify the reference is the right kind: skip references with a symbol, type-only references, and nodes whose `AstKind` is not the expected identifier or member access.
38
+
- When checking imported specifiers or exported names, iterate the concrete specifiers or precomputed export set rather than scanning all root bindings for every item.
39
+
40
+
Use precomputed `FxHashSet`s only when many symbols need the same membership test. Prefer keyed semantic lookup when each lookup already has an exact name.
37
41
38
42
### Avoid unnecessary regular expressions
39
43
40
-
Do not construct regular expressions internally when byte or string checks are enough. Prefer simple operations such as checking whether a string contains a character, starts with a prefix, ends with a suffix, or matches a small fixed set of values.
44
+
Avoid regular expressions when byte or string checks are enough: `contains`, `starts_with`, `ends_with`, or matching a small fixed set.
41
45
42
-
### Avoid heap allocations
46
+
For hot comment or string scanning paths, prefer a cheap `memchr` or byte search to reject most inputs, then parse only candidates. Preserve regex semantics when replacing one, especially identifier boundaries, optional prefixes, and multiline whitespace.
43
47
44
-
Minimize allocations in hot lint paths.
48
+
### Avoid heap allocations
45
49
46
50
- Use copy-on-write utilities when a value usually does not need to change.
47
51
- Avoid intermediate `Vec`s and `String`s when iteration or borrowed data is enough.
48
52
- Keep temporary data on the stack when practical.
49
53
- Delay allocation until a diagnostic, fix, or transformed value is actually needed.
54
+
- Use allocation-free ASCII comparisons such as `starts_with_ignore_case` before calling `cow_to_ascii_lowercase`.
55
+
- Use byte scans such as `as_bytes().array_windows()` for simple ASCII patterns like escape sequences.
56
+
- Reserve hash maps or sets when the final size is known.
57
+
- Avoid building a `HashSet` just to check names that can be looked up directly in scoping data.
0 commit comments