Repository navigation
v1.14.0
This release checks classes against your design system as a whole. Two new rules report what no
class-by-class check could: no-default-palette, a Tailwind palette color in a project with colors
of its own, and no-dynamic-classes, a class built at runtime that Tailwind never generates. An
experimental third, no-borrowed-component-styles, reports a plain element that rebuilds one of
your components. Messages name the fix — the theme colors to use, the closest scale steps — and a
misspelt setting is reported instead of silently ignored. Rule options and settings apply per file,
as oxlint's overrides and nested configs intend. A Claude Code plugin and an agent skill bring all
of it to AI coding agents. The results are measured: the new
Benchmark runs this plugin, @shadcn/lint and
eslint-plugin-better-tailwindcss over shadcn/ui's app and judges them with Tailwind itself.
Before you upgrade
-
One cold start per entry point. The design-system cache key changed, so the first run after
upgrading precomputes each entry point again. That takes seconds, not minutes. Cache files unused
for 30 days are now removed. -
Tailwind CSS v4.1.15 or newer, and Node.js
^20.19.0 || >=22.12.0. Tailwind 4.1.0–4.1.14
never worked: they crashed. They now get a cleardesignSystemUnavailable. -
Your
.oxlintrc.jsonruns only the rules it lists, so the new rules are opt-in. The
recommended config, if you copy it, now includesno-dynamic-classesaserror. -
Reports that can appear with the same config:
- a misspelt or mistyped setting (
invalidSetting, once per file); - classes in strings joined with
+; max-class-counton long template literals;- rule options from
overridesand nested configs, which now apply to their files; consistent-variant-order, if you ran--fixwith an entry point: it rewrites those chains
back to outermost-first once.
- a misspelt or mistyped setting (
-
Reports that go away:
no-dark-without-lighton dark-only classes that set no colour;- unknown-class reports of classes defined in nested stylesheets, up to four
@imports deep, and
of the static text glued to a${}; - wrong typo suggestions on short classes.
-
New message texts, if you match them in scripts:
no-hardcoded-colors(noHardcodedTokens) names your theme's colors;no-arbitrary-value(noArbitraryOptions/noArbitraryTheme) names the closest steps or the
file to add a token to;no-dark-without-light(missingBaseProperty) names the property.
All three need an entry point; without one, the messages are unchanged.
Features
-
A Claude Code plugin.
/plugin marketplace add sergioazoc/oxlint-tailwindcss, then
/plugin install oxlint-tailwindcss@oxlint-tailwindcss. It starts the project's own
oxlint --lspas a language server, so Claude sees the diagnostics on the files it opens and
edits. It also checks the files Claude edited before it finishes: when oxlint-tailwindcss reports
errors in them, Claude is sent back once with the list. Warnings and files Claude didn't touch
don't count. It bundles the agent skill, and runs the project's own oxlint and config. See
AI coding agents. -
New rule, experimental:
no-borrowed-component-styles. A<button>that copies Button's
classes — or rewrites them from memory — looks right today and drifts tomorrow: it doesn't follow
Button's changes, and it never had its focus ring, disabled state or variants. Point the rule at
your components ("components": ["src/components/ui"]) and it reports a native element whose
classes rebuild one of them, naming the component and its file (borrowedStyles: "
rebuilds Button: 9 of its 9 style declarations match. Use Button from components/ui/button.tsx
instead…"). It reads each component'scva()/tv()styles and rootclassNamewithout running
them, and compares what the classes do, not how they're written:px-4andpl-4 pr-4are the
same style, layout and variant classes don't count, a different color is a different style, and
text styles alone never match. DS-dependent, no autofix, off in the recommended config.
Experimental: its heuristics may change in a minor release. On shadcn/uiapps/v4: 1 report, a
checkbox drawn by hand inside a command-menu item. -
no-hardcoded-colorsnames your theme's colors. With an entry point, and a theme that defines
colors of its own, the message lists them —
"bg-[#ff6600]" uses a hardcoded color value. Use one of your theme colors instead: brand, brand-light.
— so the replacement is in the report. The design system is loaded only once there is a color to
report; without an entry point, or on stock Tailwind, the message is unchanged. The rule becomes
DS-optional and accepts a per-ruleentryPoint; it never reports a missing design system. Same
reports as before, only the text changes. -
New rule:
no-default-palette. In a project whose theme defines its own colors, a color from
Tailwind's default palette —bg-red-500,text-gray-900,bg-white— is usually a
design-system leak: it doesn't follow the theme, andbg-whitestays white in dark mode. The rule
reports every class that reads a palette color (with variants, opacity modifiers, and arbitrary
values that read a palette variable), and names the project's colors in the message. A palette
color the theme redefines is the project's own; with no colors of its own, the rule reports
nothing.allowtakes names or*prefixes (["white", "gray-*"]). DS-dependent, no autofix,
off in the recommended config. On shadcn/uiapps/v4: 144 reports, 18 of themwhite/black. -
A misspelt or mistyped setting is reported. oxlint doesn't check
settings, and the plugin
read each key it knew and nothing else, sorootfontsize,atributesor
"attributes": "className"(read letter by letter) changed nothing — or the wrong thing —
silently. Now the first rule to lint each file reports what's wrong withsettings.tailwindcsson
its first line, once per file: an unknown key (with the setting you likely meant), a value of the
wrong type, a pattern that isn't a regular expression, or acalleeExtractorskind that doesn't
exist (invalidSetting: "Check settings.tailwindcss: "rootfontsize" is not a setting (did you
mean "rootFontSize"?)"). Valid settings report nothing new. -
New rule:
no-dynamic-classes. Tailwind generates CSS only for class names written out in
full, so a class built at runtime —`bg-${color}-500`,`w-[${width}px]`,
`hover:${cls}`— gets no CSS and the element silently goes unstyled. The rule reports each
such class once, when the text glued to the${}starts with a Tailwind utility or variant (your
project's own ones too, with an entry point);`${base} p-4`and`icon-${name}`are
fine. No autofix. In the recommended README config aserror. On shadcn/uiapps/v4: 0 reports. -
enforce-canonicalcan tell you when a canonical form means something else in your project:
reportNonEquivalent: true(off by default). shadcn/ui shipsdata-disabled:,data-open:… as
custom variants built on:where(…), sodata-[disabled]:opacity-50— which stock Tailwind
rewrites todata-disabled:opacity-50— matches different elements there. Since #78 the rule
silently left such classes alone; with the option it reports them, naming both variants, without a
fix. The check compares against stock Tailwind on the same engine, so a selector difference stock
Tailwind has too (has-[[data-slot=x]]:vshas-data-[slot=x]:) is not reported. On shadcn/ui
apps/v4: 23 reports, alldata-[disabled]:. -
no-arbitrary-valuenames the fix. With an entry point, the report lists the closest steps
and tokens of your theme with their values, and the file to add a token to: "Closest in your
theme: w-50.5 (202px) or w-51 (204px). If none fits, add a token to src/styles.css." An exact
match is offered alone (h-[26px]→h-6.5); a value that isn't a length gets the file. New
messageIdsnoArbitraryOptions/noArbitraryTheme; without an entry point the message is
unchanged. On shadcn/uiapps/v4, 292 of the 752 reports now name exact options. -
no-arbitrary-valuecan allow runtime CSS variables:
allowVariables: 'none' | 'runtime' | 'all'(default'none', so nothing changes unless you
opt in). A value that is nothing but a variable —w-(--sidebar-width),
h-[var(--radix-select-trigger-height)]— often reads something JavaScript or an inlinestyle
sets, with no token to use instead.'runtime'allows the variables no CSS in your design system
defines and still reports the ones it does (--primaryhas a named utility);'all'allows every
pure variable reference.w-[calc(var(--x)*2)]is still an arbitrary value. The rule becomes
DS-optional: only'runtime'reads the design system. On shadcn/uiapps/v4, 167 of the rule's
752 reports are pure variable references.
Bug fixes
- Classes and variables from nested stylesheets are known. The plugin read the classes and
custom properties your own CSS defines only in the entry point and the files it imports directly,
so a class in a stylesheet imported by an imported stylesheet — even in@layer components— was
reported as unknown, and its variables as undefined. It now follows your local@imports up to
four levels, the depth whose edits already invalidate the cache; a package's stylesheet is still
read without its own imports, so Tailwind's theme stays the engine's. - Class strings built with
+are linted. The extractor skipped concatenations, so no rule
checked the classes in"flex p-4 " + extraor"flex " + (active ? "itms-center" : ""), and
no-dynamic-classescouldn't report"bg-" + color. Each string operand is now read like a
template-literal part, glued to its neighbour only where the source is —"flex " + "p-4"holds
two complete classes,"bg-" + colorone runtime class — so complete classes get every rule and
their fixes, glued fragments are left byte for byte, andno-dynamic-classesreports the runtime
class written as a template ("bg-" + color + "-500"→bg-${color}-500), including one split
over two strings ("bg-" + "red-500"), which Tailwind reads as two. New reports in projects
that build classes with+. On shadcn/uiapps/v4: none (it doesn't). consistent-variant-orderwrites chains outermost first, with or without an entry point.
Without an entry point the rule wanteddark:hover:andsm:hover:— as its docs, Tailwind's
docs and shadcn/ui write them — but with one it followed the order Tailwind registers variants in
and wanted the opposite,hover:dark:andhover:sm:, so configuring an entry point flipped the
autofix. Both now use one order: page conditions (breakpoints,dark,supports-*, container
queries) →group-*/peer-*→ what the element is (aria-*,data-*,has-*) → how it's
used (hover,focus) → form state → position (first,last), with pseudo-elements innermost
as before. The design system only says what the project's own variants are — a pseudo-element, a
barrier, or a--breakpoint-*— and a@custom-variantthe rule can't place is left where it is,
as is everything across it. Without an entry point,aria-*/data-*/has-*now go before
hover/focus/first(they used to sort last). If you ran--fixwith an entry point,
the rule rewrites those chains back once. On shadcn/uiapps/v4: 58 reports → 8.no-unknown-classeskeeps named group/peer markers valid when a custom variant names
.group. With a@custom-variantwhose selector names.groupor.peerin the entry point
(e.g.next-group-hover (&:is(:where(.group):has(~ .group:hover) *))),group/rowand
peer/fieldwere reported as unknown. The selector scan putgroup/peerinto the component
set, and the marker check refused any component base; it now refuses only component classes
Tailwind does not generate itself
(#165, reported and fixed by
@followdarko).- Tailwind 4.1.0–4.1.14 are rejected with a clear message instead of a raw engine error. The
precompute callsds.canonicalizeCandidates, which Tailwind only ships from 4.1.15, but the
version guard's floor was 4.1.0 — so those releases crashed with
ds.canonicalizeCandidates is not a functionbehind a hint to check the CSS for syntax errors.
The guard now names the real floor, v4.1.15. Those versions never worked; only the message
changes. CI pins the floor exactly and asserts that 4.1.14 is rejected by the guard. - Rule options and settings now apply per file. oxlint lints many files with one rule instance,
and the plugin compiled options and settings on the first file and kept them for the whole run. So
a rule's options from anoverridesblock or a nested.oxlintrc.jsonwere ignored (or leaked
into other files), and a nested config'sattributes,callees,tags,variablePatterns,
calleeExtractors,rootFontSizeanddebugapplied only if a file of that package happened to
be linted first — which, with several threads, changed from run to run. Each file now gets its own
config's values;entryPointwas already per file. Files of one config still share one compiled
config, so this costs nothing measurable. no-dark-without-lightonly asks for a light-mode base for colours. A dark-only filter,
display, border width or opacity —dark:brightness-[0.2] dark:grayscaleon an image,
dark:hiddenon a decoration — was reported as missing a base nobody should add; light mode keeps
the element's normal rendering on purpose. With an entry point, a variant class is checked when
the CSS it emits sets a colour (a colour property, a--color-*variable or a colour literal);
without one, the families that are never colour are skipped.dark:text-whiteon its own is still
reported. With an entry point the message now names the property (missingBaseProperty: "sets
color only under the dark variant…"). On shadcn/uiapps/v4: 11 reports → 1
(dark:text-foreground).- Autofixes no longer split a class built with
${}. In`bg-${c}-500 p-4 p-4`the static
text glued to the expression (bg-,-500) is part of one runtime class, but rules saw it as
classes of their own, and fixes re-inserted a space at the${}boundary:no-duplicate-classes
turned that string into`bg-${c} -500 p-4`, andenforce-logicalturned
`ml-2 text-${c}`into`ms-2 text- ${c}`. The same happened in
enforce-consistent-important-position,enforce-consistent-variable-syntax,
enforce-sort-orderandconsistent-variant-order(which could also move a fragment away from
its expression),enforce-shorthand,enforce-canonical,no-deprecated-classes,
enforce-negative-arbitrary-values,no-unnecessary-arbitrary-value, and in the suggestions of
no-unknown-classes,prefer-scale-tokenandprefer-theme-tokens. Glued fragments are now left
out of what these rules check and rewrite, so the dynamic class is kept byte for byte and
no-unknown-classesno longer reportsbg-or-500as unknown classes.
no-unnecessary-whitespace,enforce-consistent-line-wrappingandmax-class-countstill see
the text as written. no-unknown-classesoffers fewer wrong quick-fixes on short classes. A suggestion used to be
any known class within 3 edits, so a CSS-less marker such aslinewas offeredinline(a layout
change), andw-[]was offeredw-0. The allowance now scales with length (one edit per three
characters, from 1 to 3) for utilities and variants alike, and swapping two adjacent letters
counts as one edit, soflxe→flexandopne:→open:are still suggested. Such classes are
still reported; only the suggestion goes away.max-class-countcounts a template literal as one class string. Each part between${}was
counted on its own, so`a b c ${x} d e f`read as two strings of 3 and never reached amax
of 4. The parts are now added up and reported once, a class glued to an expression
(bg-${tone}-500) counts once, and a bare${expr}counts as none. This can add reports on
long templates. Separatecn()arguments andcva()/tv()values are still counted one by one,
since they are often conditional or alternatives; the docs used to say the count was per element
or per call, which was never the case, and now describe it as it is. The README example printed 20
classes under a "(21)" diagnostic; it now has 21.- The design-system cache notices local plugins and package upgrades. Its key covered the CSS
entry and its local@imports, but not a local@plugin/@configfile or the version of a
package the CSS imports or loads as a plugin (tw-animate-css,@tailwindcss/typography).
Editing the plugin or upgrading the package kept serving the old class list, so a class that no
longer existed stopped being reported until the cache was cleared. Both are part of the key now.
The new key means one cold precompute per entry point after upgrading. debugprints one line per file. Thefile → entry pointline came once per
design-system-dependent rule, so with four such rules on, every file was listed four times.- Tailwind insiders builds are no longer rejected as "too old".
0.0.0-insiders.<sha>was read
as version 0; it is now treated as an untested newer engine — a one-time notice, then linting as
usual.
Performance
- The disk cache no longer grows forever. Every change to a design system's CSS writes a new ~3
MB precompute, and nothing removed the old ones — in a CI cache restored run after run they piled
up. After each precompute, the plugin's own cache files unused for 30 days are removed; a cache
hit refreshes a file's date — at most once a day, so a warm run still writes nothing — and what's
in use never expires. Other files in the directory are left alone. - The precompute is about 1 s faster. It builds the map of arbitrary values to named classes
(h-[auto]→h-auto) first thing instead of late: the same Tailwind call costs about five times
as much once the canonical-forms phase has run (1.6 s instead of ~0.5 s on shadcn/ui's theme). The
result is byte for byte the same on every test theme. With the change below, a cold start on
shadcn/uiapps/v4goes from 10.8 s to 7.9 s on one thread. - An engine without
canonicalizeCandidates(Tailwind before 4.1.15, reachable only with
allowUntestedEngine) no longer fails the whole precompute: the canonical and v3-rename maps stay
empty and every other rule works. - A cold start is about 1.5 s shorter. When the design system has to be precomputed, the
enforce-canonicalworker now starts alongside it and builds Tailwind's canonicalization tables
(~1 s, once per worker) in the meantime, instead of after it on the first class that needs it. On
shadcn/uiapps/v4: 10.8 s → 9.2 s cold on one thread, with identical diagnostics; warm runs are
unchanged. debugsays where a cold start's time goes. Each design-system load now logs whether it came
from the disk cache or a fresh precompute, and how long hashing, the cache read, the precompute
and building the in-memory cache took — for a precompute, phase by phase, timed by the precompute
itself (precomputed in 3850 ms (load 20 ms, validate 402 ms, canonical 1416 ms, …)).no-unknown-classesfinds typo suggestions in about half the time. The edit-distance scan
over every known class now stops as soon as a candidate can't beat the suggestion budget, and
reuses its buffers instead of allocating per candidate. On shadcn/uiapps/v4, warm, the rule
went from 502 ms to 277 ms, with identical diagnostics.
Documentation
- The npm README is short. Installation, the full config, a generated table of every rule — what
it checks, its recommended severity, its fix, whether it needs the design system — linked to its
page, the files and frameworks it reads, and the requirements. The per-rule reference, the
settings and the edge cases are on the docs site, where they are tested; the README's copy had
drifted (it still said only first-level@imports were read). The package's description and
keywords say what it does. - An agent skill.
npx skills add sergioazoc/oxlint-tailwindcss --skill oxlint-tailwindcss
installsskills/oxlint-tailwindcss/SKILL.mdinto an AI coding agent: how to set the plugin up —
requirements, the entry point, the recommended config — and what to do about each diagnostic.
Tests keep it in line with the docs: its config runs with the real oxlint, its requirements and
rule names are the code's, and every page it links exists. - New pages: Benchmark and
Compared with other plugins (EN and ES).
oxlint-tailwindcss, @shadcn/lint and eslint-plugin-better-tailwindcss are run over shadcn/ui's
apps/v4and a set of labeled mistakes, and Tailwind itself judges the results: which mistakes
each tool catches, its false positives, its speed, and whether its fixes change what a class
string does. On that corpus, every class string--fixchanged kept its style. Every number is
generated frombench/results/latest.json, which a weekly job checks against a fresh run. - The warning and tip boxes on
/setupand/monoreporender again (EN and ES). oxfmt's
proseWraphad merged each container's opener, body and closer into one paragraph, so the page
printed a literal:::and the unclosed box wrapped everything below it. A new test keeps every
container in the docs and READMEs well-formed. - Vue, Svelte and Astro coverage is stated as it is. The setup page said the plugin lints "every
… Vue / Svelte file"; oxlint only passes plugins the<script>blocks (and Astro's frontmatter),
so template and markup classes are not checked. A new
Vue, Svelte & Astro page shows what is and
isn't linted, and an end-to-end test with canaries keeps the docs honest when oxlint changes it. /monorepoexplains where options and settings can vary per package (overridesfor options
only, nested configs for both, Vite+ and editor caveats), and its Pattern B example now uses
"extends": ["../../.oxlintrc.json"]: the string form it showed is rejected by oxlint
(expected a sequence).- New Running in CI page (EN and ES): pull-request
annotations with-f github, keeping the design-system precompute between jobs with
actions/cacheandOXLINT_TAILWINDCSS_CACHE_DIR, per-rule timings with--debug timings(which
print nothing with-f github), and what to trust in a restored cache. A new e2e test holds the
cache-directory behavior it describes. /settingslists the environment variables —DEBUG,OXLINT_TAILWINDCSS_CACHE_DIR(which
was undocumented) andOXLINT_TAILWINDCSS_WORKER_REQUEST_TIMEOUT— and itsdebugsection lists
what is actually logged; it promised "cache hits", which are never logged.- The v0 → v1 migration guide is accurate for today's versions. It pointed at the v0.x cache
directory without saying the cache moved to a per-user directory in v1.3, and said every timeout
was set bysettings.tailwindcss.timeout; that setting only moves the precompute timeout. - The docs site stops publishing its internal files. Every
rules/_extras/*fragment (48 pages,
EN and ES) and the agent notes were served as pages of their own; they are excluded now, and their
old URLs redirect to the rule page. A dead internal link fails the docs build, "Edit this page" on
a rule page opens the file the page is generated from, and the Spanish site's theme labels
(search, outline, pager, 404…) are in Spanish. - The docs are checked against the code. New tests hold the rule count and lists, each rule's
defaults and design-system group, every documented option and setting, the environment variables,
the default extractor lists and the version floors, plus page-by-page parity between English and
Spanish. They caught four gaps, now fixed:no-unknown-classesdidn't document itsentryPoint
option,/settingsnever namedexclude, the README's full setup snippet left out
prefer-scale-token, and a typo. - Every docs page has its own title and description, in its own language. All pages shared the
site-wide English description — Spanish pages included — and rule pages were titled with the bare
rule name. Each rule page now opens with a one-sentence definition (also its search description)
and an "At a glance" table — autofix, editor suggestions, whether it needs the design system, its
options — generated from the rule's metadata. - The docs site names itself to search engines. Google showed "Cloudflare" as the site name for
our pages: the site had no name signal of its own, and thepages.devroot it lives under
redirects to cloudflare.com. The home page now declares aWebSite(structured data) named
oxlint-tailwindcss, matched byog:site_name, the home title and the npmhomepage, which now
points at the docs. Every page gains a canonical URL, English/Spanish alternates, link-preview
tags and image, and a favicon; rule pages get breadcrumbs; the 404 page is kept out of the index,
and<html lang>isen/es. - The docs site is easy to crawl and to feed to an AI assistant. A
sitemap.xmlwith
English/Spanish alternates, its ownrobots.txt(search and AI use welcome, via Content Signals),
andllms.txt/
llms-full.txtplus a markdown copy of
every page (/setup.md,/rules/no-unknown-classes.md), each linked from its HTML page. - One recommended config.
/setup's starter set and the README's config disagreed (different
rules,no-duplicate-classeserrorin one andwarnin the other). Both are now generated from
arecommendedseverity in each rule's metadata, and so is the README's rule list by category.
The four categories are Correctness, Modernization, Consistency and Design-system guardrails. - The oxfmt / Prettier interop claims hold, with the setting they were missing. The docs said
the formatter andenforce-sort-order"agree byte-for-byte if they read the same CSS"; that also
needs the formatter'sfunctions(tailwindFunctionsfor Prettier) to list your class helpers —
otherwisecn("p-4 flex")stays unsorted — and it covers only the strings the formatter formats.
/interopnow says who formats what, that the formatter also drops duplicates and collapses
whitespace, and thatoxlint --fixapplies one fix per class string per run (it has no multi-pass
fixing), with the snippets updated. A new end-to-end test with the real oxlint and oxfmt holds
each of these. - Every example on the rule pages runs as a test, in English and Spanish. Each ✗ example must be
reported by its rule and each ✓ example must not be, with the options it states, and the fixed
result shown after→must be whatoxlint --fixwrites. That caught examples that didn't do
what they said: theenforce-consistent-line-wrappingexamples named their variablescardClass
/buttonClass, which the plugin doesn't read by default (onlyclassName,classNames,
classesandstyles), so neither the ✗ nor the ✓ one was ever checked; the
no-unnecessary-whitespace"tab" example wrote the escape\t, not a tab;no-unknown-classes
called"hover:" + dynamicSuffixan "allowlisted" class, though nothing allowlisted it (the
example now usesallowlistandignorePrefixes); and the options several pages described in
prose are now given as real config. Pages with an autofix now show the fixed line for every ✗
example. The README's hero example is checked the same way. - New shadcn/ui and @shadcn/lint page (EN and
ES): what each plugin reports when both run — restyled components, inline styles and palette
colors are @shadcn/lint's; conflicts, duplicates, deprecated and non-canonical classes, dark
variants without a light base and order are this plugin's; both report unknown classes and
arbitrary values — a combined.oxlintrc.jsonthat reports each problem once, what
no-conflicting-classesfinds in shadcn/ui's own select trigger, and the setup step by step for a
person or an agent. The table is generated from data and checked against both plugins: this
plugin's column in the test suite, @shadcn/lint's weekly against its latest release. - New
migration guide from eslint-plugin-better-tailwindcss
(EN and ES): each of its 15 rules and its settings mapped to this plugin's, with what differs in
their options, the switch step by step with a before-and-after config, and the rules it doesn't
have. Every row's example is reported by both of its rules, checked weekly against
better-tailwindcss's latest release. - New FAQ (EN and ES), every answer checked against
oxlint: ESLint and Tailwind v3, which rules run (oxlint'scategoriesdon't turn on a JS plugin's
rules), the entry point, Vue and Svelte, why a class that works can be reported as unknown,
turning a rule off for a line,--fix, formatters, @shadcn/lint, better-tailwindcss, CI and
monorepos. The home page now says what the plugin is and what it catches, with a quick start; the
sidebar groups the guides; and the docs build fails on a link to a heading that doesn't exist. - Every "Tailwind v4.1+" requirement now reads v4.1.15+.
- The Node.js requirement matches oxlint's own range,
^20.19.0 || >=22.12.0, andengines
says so: oxlint itself does not run on older Node 20 releases. CI now smoke-tests the documented
floors — oxlint 1.43.0, and Node 20.19.0 — so both claims stay true.
Dependencies updated: oxlint / @oxlint/plugins 1.85, oxfmt 0.70, vitest 5.0.1, pnpm 12.6.
Dependencies
- The runtime dependencies are unchanged:
@tailwindcss/nodeandtailwindcss, loaded from your
project.engines.nodeis now^20.19.0 || >=22.12.0, the range oxlint itself requires. - Developed and tested with oxlint 1.85, oxfmt 0.70, vitest 5.0.2 and pnpm 12. CI adds Node 26 and
smoke-tests the documented floors (oxlint 1.43.0, Node 20.19.0, Tailwind 4.1.15).