basalt-ui 1.33.0 → 1.34.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.
Files changed (82) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +26 -0
  3. package/MIGRATING.md +108 -15
  4. package/README.md +3 -0
  5. package/agent/skills/basalt-app/SKILL.md +5 -3
  6. package/configs/oxlint-basalt.json +33 -0
  7. package/configs/oxlint-plugin.js +21 -6
  8. package/configs/oxlint-plugin.test.ts +98 -10
  9. package/configs/oxlint.json +2 -30
  10. package/dist/cli/check-theme.d.ts.map +1 -1
  11. package/dist/cli/check-theme.js +37 -36
  12. package/dist/cli/doctor.d.ts.map +1 -1
  13. package/dist/cli/doctor.js +3 -5
  14. package/dist/cli/guard-hook.d.ts.map +1 -1
  15. package/dist/cli/guard-hook.js +6 -34
  16. package/dist/cli/index.d.ts +29 -61
  17. package/dist/cli/index.d.ts.map +1 -1
  18. package/dist/cli/index.js +63 -19
  19. package/dist/cli/sync.d.ts.map +1 -1
  20. package/dist/cli/sync.js +7 -16
  21. package/dist/common/vx-families.d.ts +7 -0
  22. package/dist/common/vx-families.d.ts.map +1 -0
  23. package/dist/common/vx-families.js +32 -0
  24. package/dist/common/vx-family.d.ts +11 -0
  25. package/dist/common/vx-family.d.ts.map +1 -0
  26. package/dist/common/vx-family.js +12 -0
  27. package/dist/guard/index.d.ts +2 -2
  28. package/dist/guard/index.d.ts.map +1 -1
  29. package/dist/guard/index.js +11 -13
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +0 -2
  33. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  34. package/dist/shell/app-mobile-nav.js +2 -1
  35. package/dist/shell/app-mobile-nav.module.css +12 -0
  36. package/dist/shell/app-sidebar.d.ts.map +1 -1
  37. package/dist/shell/app-sidebar.js +32 -36
  38. package/dist/shell/app-sidebar.module.css +6 -0
  39. package/dist/shell/index.d.ts +0 -1
  40. package/dist/shell/index.d.ts.map +1 -1
  41. package/dist/shell/index.js +0 -2
  42. package/dist/shell/nav-glyph.d.ts +14 -0
  43. package/dist/shell/nav-glyph.d.ts.map +1 -0
  44. package/dist/shell/nav-glyph.js +21 -0
  45. package/dist/shell/nav-types.d.ts +1 -0
  46. package/dist/shell/nav-types.d.ts.map +1 -1
  47. package/dist/shell/sidebar-search.d.ts.map +1 -1
  48. package/dist/shell/sidebar-search.js +1 -3
  49. package/dist/surfaces.d.ts +2 -2
  50. package/dist/surfaces.js +2 -2
  51. package/dist/tokens/index.d.ts +1 -1
  52. package/dist/tokens/index.d.ts.map +1 -1
  53. package/dist/tokens/index.js +17 -1
  54. package/dist/tokens/size-classes.d.ts +12 -0
  55. package/dist/tokens/size-classes.d.ts.map +1 -1
  56. package/dist/tokens/size-classes.js +11 -5
  57. package/llms.txt +4 -4
  58. package/package.json +1 -1
  59. package/src/cli/check-theme.ts +60 -37
  60. package/src/cli/doctor.ts +3 -5
  61. package/src/cli/guard-hook.ts +8 -35
  62. package/src/cli/index.ts +102 -91
  63. package/src/cli/sync.ts +7 -16
  64. package/src/common/vx-families.ts +36 -0
  65. package/src/common/vx-family.ts +22 -0
  66. package/src/guard/index.ts +22 -25
  67. package/src/index.ts +0 -2
  68. package/src/shell/app-mobile-nav.module.css +12 -0
  69. package/src/shell/app-mobile-nav.tsx +8 -1
  70. package/src/shell/app-sidebar.module.css +6 -0
  71. package/src/shell/app-sidebar.tsx +52 -50
  72. package/src/shell/index.tsx +0 -1
  73. package/src/shell/nav-glyph.tsx +38 -0
  74. package/src/shell/nav-types.ts +1 -0
  75. package/src/shell/sidebar-search.tsx +1 -5
  76. package/src/surfaces.ts +2 -2
  77. package/src/tokens/index.ts +28 -1
  78. package/src/tokens/size-classes.ts +18 -5
  79. package/dist/shell/use-breakpoint.d.ts +0 -10
  80. package/dist/shell/use-breakpoint.d.ts.map +0 -1
  81. package/dist/shell/use-breakpoint.js +0 -11
  82. package/src/shell/use-breakpoint.ts +0 -37
package/AGENTS.md CHANGED
@@ -8,7 +8,7 @@ Toolchain: Bun runtime, oxlint + oxfmt, conventional commits (empty scope), `mas
8
8
 
9
9
  | Subpath | Layer | Purpose |
10
10
  | --------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
- | `basalt-ui` | mantine-coupled | BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass (useBreakpoint on notice), NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock) |
11
+ | `basalt-ui` | mantine-coupled | BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock) |
12
12
  | `basalt-ui/charts` | headless | CartesianChart + visx chart primitives, kinds, sparklines, hooks, and token re-exports (Mantine-free) |
13
13
  | `basalt-ui/tokens` | headless | VX token refs, buildPaletteCss, defineSeries, seriesTokens, groupTokens, alpha (Mantine-free) |
14
14
  | `basalt-ui/theme-lab` | mantine-coupled | ThemeLabControls, applyOverrides, COLOR_GROUPS — a low-level inspector for the non-derived structural tokens; identity/color tuning lives in DeriveControls |
package/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ # [1.34.0](https://github.com/jkrumm/basalt-ui/compare/v1.33.0...v1.34.0) (2026-10-01)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * --merge-lint replaces a guards-only extends instead of stacking it ([b2e551b](https://github.com/jkrumm/basalt-ui/commit/b2e551bc1dc431a457f58db2f8727c5f2546a9f2))
7
+ * card-with-border remedy names its card-inset half ([1edfae7](https://github.com/jkrumm/basalt-ui/commit/1edfae79a0366d0f6c4618a7bd07d8c2370a1753))
8
+ * derive basalt's --vx-* families from every emitted name ([07ea183](https://github.com/jkrumm/basalt-ui/commit/07ea1834f4cfc14979bb81e4cd2afc5849f28712))
9
+ * dev-gate the basalt-family ref warning and pin its version ([23396df](https://github.com/jkrumm/basalt-ui/commit/23396df7d4fbb1f7b16f0d2f192c07485b6a4e47))
10
+ * give icon-less nav items a first-letter glyph and a name in the rail ([9095f15](https://github.com/jkrumm/basalt-ui/commit/9095f157d1652316f03e2ff1668faddb406a34ef))
11
+ * name an icon-less row by aria-label only in the collapsed rail ([bc13e09](https://github.com/jkrumm/basalt-ui/commit/bc13e09ff3c12e56be98c5353cf95c5925463ff9))
12
+ * never autofix a removed deprecation row ([0534a28](https://github.com/jkrumm/basalt-ui/commit/0534a287da5252b8699b9bd4eb5ec36c1279b1b9))
13
+ * refuse a release that reaches a deprecation's removeIn while it still ships ([eb55145](https://github.com/jkrumm/basalt-ui/commit/eb5514507011e9b9fdb7f1a23e335bc1c478c3aa))
14
+ * restore check-grace's singular 'grace entry' in the clear line ([6fca61c](https://github.com/jkrumm/basalt-ui/commit/6fca61cb5ec1dae71b1f8b9661817a17919ca9b5))
15
+ * take the rail glyph from a real grapheme via Intl.Segmenter ([ff4e396](https://github.com/jkrumm/basalt-ui/commit/ff4e39637f12cddb8817cd4be9367bb63f0ab5fc))
16
+ * treat a false icon as absent and expose a label-only glyph helper ([323ddbb](https://github.com/jkrumm/basalt-ui/commit/323ddbb0dc28c41b54c1c33271eb7d6a348ab1bd))
17
+
18
+
19
+ ### Features
20
+
21
+ * check-theme names an unwired AST lane ([91472ef](https://github.com/jkrumm/basalt-ui/commit/91472efbf87b336716c1871392878e648b355cd0))
22
+ * judge every unemitted name inside a basalt-owned --vx-* family ([4864a9d](https://github.com/jkrumm/basalt-ui/commit/4864a9d78a0a0ef95d1f6caee85043b0d64c75ea))
23
+ * remove useBreakpoint, overdue since 1.33.0 ([d68f538](https://github.com/jkrumm/basalt-ui/commit/d68f538dde34acecda481f567c17ade5a86074d4))
24
+ * ship a guards-only oxlint preset, configs/oxlint-basalt.json ([f96d150](https://github.com/jkrumm/basalt-ui/commit/f96d15097aabf5461b524270eb5ce523928bfab5))
25
+ * ship CONTAINER_KEYS for SimpleGrid type="container" keys ([acb5933](https://github.com/jkrumm/basalt-ui/commit/acb5933cf407cfb203819ad09bb7cf0315f73e79))
26
+
1
27
  # [1.33.0](https://github.com/jkrumm/basalt-ui/compare/v1.32.1...v1.33.0) (2026-10-01)
2
28
 
3
29
 
package/MIGRATING.md CHANGED
@@ -66,18 +66,18 @@ There is one row per SURFACE, not per export, and a surface earns a row once any
66
66
  shipped lefthook preset both changed in 1.30.0 with no row that owned them — which is how a
67
67
  consumer read this index, found nothing, and diffed a KPI row that had silently gone 4-up → 2-up.
68
68
 
69
- | Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | Unreleased |
70
- | ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------- |
71
- | **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | — |
72
- | **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — |
73
- | **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | — |
74
- | **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — |
75
- | **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — |
76
- | **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — |
77
- | **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — |
78
- | **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — |
79
- | **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — |
80
- | **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — |
69
+ | Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | Unreleased |
70
+ | ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ---------- |
71
+ | **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — |
72
+ | **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — |
73
+ | **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — |
74
+ | **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — |
75
+ | **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — |
76
+ | **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — |
77
+ | **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — |
78
+ | **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — |
79
+ | **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — |
80
+ | **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — |
81
81
 
82
82
  ---
83
83
 
@@ -86,6 +86,97 @@ consumer read this index, found nothing, and diffed a KPI row that had silently
86
86
  _Nothing yet. Author the next section under this heading as `## Unreleased — <title>`; the
87
87
  release renames it and opens a new one here._
88
88
 
89
+ ## 1.34.0 — the 1.34.0 minor
90
+
91
+ ### `CONTAINER_KEYS` — the `SimpleGrid type="container"` keys ship
92
+
93
+ `basalt-ui/tokens` exports `CONTAINER_CLASSES` as the CSS lengths `SimpleGrid type="container"`
94
+ keys take (`compact` 240px · `regular` 480px · `wide` 800px), so the computed key is one import
95
+ instead of a template literal at every call site (argo: 19 sites behind two local `CQ_*` consts).
96
+ `micro` has no key — `base` is that class. `basalt/raw-breakpoint` judges theme names only, so the
97
+ computed key is green; nothing to waive.
98
+
99
+ ```tsx
100
+ import { CONTAINER_KEYS as CQ } from 'basalt-ui/tokens'
101
+ ;<SimpleGrid type="container" cols={{ base: 1, [CQ.regular]: 2, [CQ.wide]: 3 }}>
102
+ …
103
+ </SimpleGrid>
104
+ ```
105
+
106
+ | Delete | Replace with |
107
+ | --------------------------------------------------------------------------------------------- | -------------------------- |
108
+ | ``[`${CONTAINER_CLASSES.regular}px`]`` (or `.wide` / `.compact`) as a key | `[CONTAINER_KEYS.regular]` |
109
+ | a local ``CQ_REGULAR = `${CONTAINER_CLASSES.regular}px` `` const (argo's `container-grid.ts`) | the import above |
110
+
111
+ `Grid type="container"` is unchanged: `breakpoints={CONTAINER_GRID_BREAKPOINTS}` (§ 1.33.0) stays
112
+ its answer, and that map is now built from `CONTAINER_KEYS` — same values.
113
+
114
+ ### `useBreakpoint` — removed from `basalt-ui`
115
+
116
+ | Was | Now |
117
+ | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
118
+ | `useBreakpoint` — removed from `basalt-ui` | shell chrome: `useSizeClass() !== 'compact'` for `'sm'`, `useSizeClass() === 'expanded'` for `'lg'`; a page's own layout swap: a `type="container"` SimpleGrid/Grid or an `@container` rule (§ 1.32.0 `basalt/raw-breakpoint`) |
119
+ | `BreakpointName` — removed from `basalt-ui` | — (no replacement; `SizeClass` is the shell's vocabulary) |
120
+
121
+ On notice since 1.31.0, dated twice (1.31.0 → 1.33.0) and shipped one minor past that date; measured
122
+ fleet usage at removal was zero. The fix was never autofixable (the replacement is a different
123
+ shape), so `basalt/deprecated-export` keeps its row through 1.34.0 only to say the import is gone
124
+ instead of "still resolves".
125
+
126
+ ### Guards — `unknown-vx-token` judges basalt's families in full (`warn`, `error` moves to 1.35.0)
127
+
128
+ `var(--vx-surface-2, transparent)` rendered transparent in image-gen since the file was written,
129
+ and 1.33.0 said nothing: it judged only removed names and bare roots, because `groupTokens` could
130
+ emit any name. Now:
131
+
132
+ - **Judged: every unemitted name inside a basalt-owned family** — the leading lowercase run of the
133
+ name: `accent`, `fill`, `ink`, `line`, `radius`, `shadow`, `space`, `status`, `surface`, `text`,
134
+ `tooltip`, … (the full list is in the finding's remedy, generated from what basalt emits). So
135
+ `--vx-surface-2`, `--vx-ink3`, `--vx-space-gutter` and a bare `--vx-space` are all findings.
136
+ - **Not judged: a name in any other family** (argo's `--vx-activity-*`, rb's `--vx-confidence-*`),
137
+ a computed name, and a name the same file declares.
138
+ - **`groupTokens` / `seriesTokens` warn** (once per name) on a ref inside a basalt family —
139
+ `groupTokens('surface', …)`, a series key `ink3` — and **throw from 1.35.0**, when the kind
140
+ promotes. That refusal is what makes the guard's judgement sound. Rename the group
141
+ (`groupTokens('app', …)`), and its `buildPaletteCss` `groups` key with it. Measured: no consumer
142
+ names one. `on` is not judged: the theme emits `--vx-on-<color>` for your own colors too.
143
+
144
+ Widening restarts the grace: `warn` through 1.34.x, `error` at 1.35.0. Measured at ship time:
145
+ argo, rb, image-gen, image-share, email-gateway, linewatch, obsidian, weatherorb all at 0
146
+ (image-gen's one hit was already fixed by hand in r4).
147
+
148
+ ### `check-theme` says when the AST lane is not wired
149
+
150
+ When the nearest `.oxlintrc.json` up to the repo root neither extends a shipped preset nor loads
151
+ `configs/oxlint-plugin.js` with `basalt/*` rules on (or the target does not resolve), `check-theme`
152
+ prints one line — `AST lane not enforced — N basalt/* rule ids unguarded (incl. the promoted
153
+ control-outside-home, raw-breakpoint)`. Information only; the exit code is unchanged. `basalt-ui
154
+ doctor` names the fix.
155
+
156
+ ### `card-with-border` names its `card-inset` half
157
+
158
+ Dropping `withBorder` and keeping `padding="md"` satisfied `check-theme` and then failed oxlint's
159
+ `basalt/card-inset`. The text-lane remedy now says to fix the inset in the same edit.
160
+
161
+ ### `configs/oxlint-basalt.json` — the guard lane without the generic preset
162
+
163
+ Wiring `configs/oxlint.json` into a repo with history turns on the generic jsx-a11y / unicorn /
164
+ import / promise set alongside the `basalt/*` rules, and email-gateway hit unrelated errors before a
165
+ single guard could land. The new guards-only preset is the `basalt/*` plugin rules at their shipped
166
+ levels and nothing else:
167
+
168
+ ```json
169
+ { "extends": ["./node_modules/basalt-ui/configs/oxlint-basalt.json"] }
170
+ ```
171
+
172
+ Take it first, move to `configs/oxlint.json` when the generic debt is paid. The full preset now
173
+ `extends` the guards-only one, so every `basalt/*` level lives in one file; extending the full one
174
+ behaves exactly as before. `doctor` and `check-theme` accept either.
175
+
176
+ The full preset assumes the shipped `tsconfig.react-app.json` base (`lib: ES2023`): its
177
+ `unicorn/no-array-sort` warning steers to `toSorted()`, which an older `lib` does not type. Extend
178
+ that tsconfig rather than waiving the rule.
179
+
89
180
  ## 1.33.0 — the 1.33.0 minor
90
181
 
91
182
  ### `CONTAINER_GRID_BREAKPOINTS` — the `Grid type="container"` map ships
@@ -113,7 +204,8 @@ The trust is provenance-gated: the import must name `CONTAINER_GRID_BREAKPOINTS`
113
204
  `tokens.CONTAINER_GRID_BREAKPOINTS` on `import * as tokens`, and a same-file `const bp = …` of
114
205
  either all count; a parameter or inner `const` that shadows the name does not). A map of your own
115
206
  that deviates from it — a 1200px `xl`, say — stays a same-file literal. `SimpleGrid type="container"` is unchanged: its keys
116
- are CSS lengths, so ``[`${CONTAINER_CLASSES.regular}px`]`` stays the form.
207
+ are CSS lengths, so ``[`${CONTAINER_CLASSES.regular}px`]`` stays the form (from 1.34.0:
208
+ `[CONTAINER_KEYS.regular]`, § 1.34.0).
117
209
 
118
210
  ### State and controls — `resets: ['page']`, `NumberFilter clearable`
119
211
 
@@ -347,8 +439,9 @@ source, which is what the rule's exemption is built on:
347
439
  <Grid><Grid.Col span={{ base: 12, lg: 4 }}>…</Grid.Col></Grid>
348
440
 
349
441
  // after — the grid's own width
350
- import { CONTAINER_CLASSES as C, CONTAINER_GRID_BREAKPOINTS } from 'basalt-ui/tokens'
351
- <SimpleGrid type="container" cols={{ base: 1, [`${C.regular}px`]: 3 }}>…</SimpleGrid>
442
+ import { CONTAINER_KEYS as CQ, CONTAINER_GRID_BREAKPOINTS } from 'basalt-ui/tokens'
443
+ // CONTAINER_KEYS ships from 1.34.0; before it, [`${CONTAINER_CLASSES.regular}px`]
444
+ <SimpleGrid type="container" cols={{ base: 1, [CQ.regular]: 3 }}>…</SimpleGrid>
352
445
  // the shipped map (§ 1.33.0); on 1.32.x, a same-file literal of the same five keys
353
446
  <Grid type="container" breakpoints={CONTAINER_GRID_BREAKPOINTS}>
354
447
  <Grid.Col span={{ base: 12, md: 4 }}>…</Grid.Col>
package/README.md CHANGED
@@ -872,6 +872,9 @@ The `./configs/*` export gives consumer apps raw presets to `extends` or copy vi
872
872
  { "extends": ["./node_modules/basalt-ui/configs/oxlint.json"] }
873
873
  ```
874
874
 
875
+ `configs/oxlint-basalt.json` is the guard lane alone — the `basalt/*` rules, none of the generic
876
+ jsx-a11y / unicorn / import set — for a repo with history to take first; `oxlint.json` extends it.
877
+
875
878
  `tsconfig.json` `extends` resolves the SAME way, through package exports (`bundler`
876
879
  `moduleResolution`, CI-verified by `scripts/pack-test.sh`) — three raw presets, `base` (the shared
877
880
  strict flags), `react-app` (`base` + DOM/JSX libs) and `node` (`base` + Node types):
@@ -27,9 +27,11 @@ once and yours forever. Claude Code cannot load rules or skills out of `node_mod
27
27
  only reason anything is copied at all; everything a MACHINE reads is an `extends` reference into
28
28
  `node_modules/basalt-ui/configs/`, so the toolchain auto-updates with the package.
29
29
 
30
- **`init` on an existing app is a lint-debt event, not a no-op** — read
31
- `.claude/rules/basalt-batteries.md` § "App bootstrapping" for what it turns on and what keeping your
32
- own `.oxlintrc.json` costs.
30
+ **`init` on an existing app is a lint-debt event, not a no-op** — `.claude/rules/basalt-batteries.md`
31
+ § "App bootstrapping" says what it turns on. Too much at once? Extend `configs/oxlint-basalt.json`
32
+ (the basalt/\* guards alone, no generic jsx-a11y/unicorn set) first, `configs/oxlint.json` later —
33
+ the full one pairs with the shipped `tsconfig.react-app.json` (ES2023 lib: `unicorn/no-array-sort`
34
+ steers to `toSorted()`).
33
35
 
34
36
  ## 2. Wire the runtime (the CLI scaffolds files, not your app's composition)
35
37
 
@@ -0,0 +1,33 @@
1
+ {
2
+ "jsPlugins": ["./oxlint-plugin.js"],
3
+ "rules": {
4
+ "basalt/no-raw-font-size": "error",
5
+ "basalt/raw-size-literal": "error",
6
+ "basalt/card-inset": "error",
7
+ "basalt/chart-in-raw-surface": "error",
8
+ "basalt/hand-rolled-plot": "error",
9
+ "basalt/chart-legend-literal": "error",
10
+ "basalt/shadow-basalt-export": "warn",
11
+ "basalt/hand-rolled-shell": "error",
12
+ "basalt/raw-scroll-container": "error",
13
+ "basalt/hand-rolled-filter": "error",
14
+ "basalt/control-outside-home": "error",
15
+ "basalt/bound-control-outside-home": "error",
16
+ "basalt/control-size-literal": "error",
17
+ "basalt/page-bar-budget": "error",
18
+ "basalt/in-body-page-title": "error",
19
+ "basalt/responsive-twin": "error",
20
+ "basalt/search-literal-link": "error",
21
+ "basalt/use-search-from-literal": "error",
22
+ "basalt/provider-above-router": "error",
23
+ "basalt/query-fn-unwrap": "error",
24
+ "basalt/deprecated-export": "warn",
25
+ "basalt/forms-field-key": "error",
26
+ "basalt/visx-boundary": "error",
27
+ "basalt/visx-tooltip": "error",
28
+ "basalt/agent-resume-guard": "error",
29
+ "basalt/agent-no-raw-usechat": "error",
30
+ "basalt/ai-sdk-major": "error",
31
+ "basalt/raw-breakpoint": "error"
32
+ }
33
+ }
@@ -3623,6 +3623,7 @@ const queryFnUnwrap = {
3623
3623
  * prop?: string
3624
3624
  * replacement: string
3625
3625
  * removeIn: string
3626
+ * removed?: true
3626
3627
  * fix?: false
3627
3628
  * }} DeprecatedExport
3628
3629
  */
@@ -3646,7 +3647,12 @@ const queryFnUnwrap = {
3646
3647
  * `removeIn` at least one minor out, add the `MIGRATING.md` row, and this rule starts nudging.
3647
3648
  * `oxlint-plugin.test.ts` scans every `src/**\/index.ts(x)` barrel for a JSDoc `@deprecated` and
3648
3649
  * fails when one has no row here, so the barrel half cannot be forgotten. Removing the export is a
3649
- * separate commit that deletes the row in the same change.
3650
+ * separate commit that either deletes the row (the fix is manual from then on — say so in the
3651
+ * removal's MIGRATING row) or keeps it one minor past the removal with `removed: true` and
3652
+ * `removeIn` set to the removing minor, so the message reads "was removed in X" instead of "still
3653
+ * resolves" — and never autofixes, whatever `fix` says. `scripts/check-grace.ts` refuses a release
3654
+ * at or past a `removeIn` whose export still ships — the gap that let `useBreakpoint` outlive its
3655
+ * date twice.
3650
3656
  *
3651
3657
  * @type {readonly DeprecatedExport[]}
3652
3658
  */
@@ -3662,8 +3668,8 @@ export const DEPRECATED_EXPORTS = [
3662
3668
  name: 'useBreakpoint',
3663
3669
  replacement:
3664
3670
  'useSizeClass() for shell chrome; a page’s own layout swap is a container decision — a type="container" SimpleGrid/Grid or an @container rule',
3665
- removeIn: '1.33.0',
3666
- fix: false,
3671
+ removeIn: '1.34.0',
3672
+ removed: true,
3667
3673
  },
3668
3674
  ]
3669
3675
 
@@ -3672,6 +3678,13 @@ function deprecatedExportMessage(row) {
3672
3678
  row.prop === undefined
3673
3679
  ? `\`${row.name}\` from ${row.subpath}`
3674
3680
  : `\`${row.prop}\` on <${row.name}>`
3681
+ if (row.removed === true) {
3682
+ return (
3683
+ `Removed basalt export — ${what} was removed in ${row.removeIn} and no longer resolves; use ` +
3684
+ `\`${row.replacement}\` instead (packages/basalt-ui/MIGRATING.md carries the row). ` +
3685
+ '(basalt/deprecated-export)'
3686
+ )
3687
+ }
3675
3688
  return (
3676
3689
  `Deprecated basalt export — ${what} is superseded by \`${row.replacement}\` and is removed in ` +
3677
3690
  `${row.removeIn}. It still resolves today, so nothing is broken yet; migrate before that minor ` +
@@ -3724,7 +3737,8 @@ const deprecatedExport = {
3724
3737
  context.report({
3725
3738
  node: spec,
3726
3739
  message: deprecatedExportMessage(row),
3727
- ...(row.fix === false
3740
+ // A removed row's replacement is prose for a gone import, never a drop-in name.
3741
+ ...(row.fix === false || row.removed === true
3728
3742
  ? {}
3729
3743
  : { fix: (fixer) => fixer.replaceText(spec, `${row.replacement} as ${local}`) }),
3730
3744
  })
@@ -4186,12 +4200,13 @@ const RAW_BREAKPOINT_EXEMPT_FILE = /(?:^|[\\/])(?:use-media-query\.ts|ChartToolt
4186
4200
  * (`CONTAINER_CLASSES`, `basalt-ui/tokens`: compact 240 / regular 480 / wide 800), never on the
4187
4201
  * viewport — `useSizeClass()` is the shell's seam, not a page's. Mantine 9's own `type="container"`
4188
4202
  * grids are the primitive: both self-wrap in an `inline-size` container, so they need no ancestor.
4189
- * The px literals are `CONTAINER_CLASSES` written out (the plugin cannot import TS source);
4203
+ * The px literals are `CONTAINER_KEYS` written out (the plugin cannot import TS source);
4190
4204
  * `oxlint-plugin.test.ts` asserts every one against it, and the MIGRATING recipe too.
4191
4205
  */
4192
4206
  export const RAW_BREAKPOINT_RECIPE =
4193
4207
  'A page’s own layout keys on its container: <SimpleGrid type="container" cols={{ base: 1, ' +
4194
- "'480px': 2, '800px': 3 }}> (px keys = CONTAINER_CLASSES, basalt-ui/tokens), or <Grid " +
4208
+ '[CONTAINER_KEYS.regular]: 2, [CONTAINER_KEYS.wide]: 3 }}> (basalt-ui/tokens; the keys are ' +
4209
+ "the px lengths '480px'/'800px'), or <Grid " +
4195
4210
  'type="container" breakpoints={CONTAINER_GRID_BREAKPOINTS}> (basalt-ui/tokens), with Grid.Col ' +
4196
4211
  'span={{ base: 12, sm: 6 }} keyed through that map; a Flex direction swap becomes that SimpleGrid (equal ' +
4197
4212
  'columns), a wrapping Group, or a CSS-module @container basalt-grid rule. useSizeClass() is for ' +
@@ -644,7 +644,7 @@ describe('basalt/ai-sdk-major', () => {
644
644
  describe('basalt/raw-scroll-container promotion', () => {
645
645
  it('ships "error" (not "warn"/"off") in the consumer preset', () => {
646
646
  const shipped = JSON.parse(
647
- readFileSync(resolve(import.meta.dirname, 'oxlint.json'), 'utf8'),
647
+ readFileSync(resolve(import.meta.dirname, 'oxlint-basalt.json'), 'utf8'),
648
648
  ) as { rules: Record<string, unknown> }
649
649
  expect(shipped.rules['basalt/raw-scroll-container']).toBe('error')
650
650
  })
@@ -682,7 +682,7 @@ describe('basalt agent rules promotion', () => {
682
682
  '%s ships "error" (not "warn"/"off") in the consumer preset',
683
683
  (rule) => {
684
684
  const shipped = JSON.parse(
685
- readFileSync(resolve(import.meta.dirname, 'oxlint.json'), 'utf8'),
685
+ readFileSync(resolve(import.meta.dirname, 'oxlint-basalt.json'), 'utf8'),
686
686
  ) as { rules: Record<string, unknown> }
687
687
  expect(shipped.rules[rule]).toBe('error')
688
688
  },
@@ -1402,7 +1402,9 @@ describe('twin lanes share one promotion', () => {
1402
1402
  })
1403
1403
 
1404
1404
  describe('PLUGIN_RULE_GRACE', () => {
1405
- const shipped = JSON.parse(readFileSync(resolve(import.meta.dirname, 'oxlint.json'), 'utf8')) as {
1405
+ const shipped = JSON.parse(
1406
+ readFileSync(resolve(import.meta.dirname, 'oxlint-basalt.json'), 'utf8'),
1407
+ ) as {
1406
1408
  rules: Record<string, unknown>
1407
1409
  }
1408
1410
  const pkgVersion = (
@@ -3357,8 +3359,26 @@ describe('basalt/query-fn-unwrap', () => {
3357
3359
 
3358
3360
  // ── deprecated-export (B4) ───────────────────────────────────────────────────
3359
3361
 
3360
- // deprecated-export's behaviour tests were removed with the last ledger row in 1.29.0; the
3361
- // ledger-shape and barrel-scan assertions below keep the mechanism honest until the next row.
3362
+ describe('basalt/deprecated-export', () => {
3363
+ it('reports a removed row as gone, never as "still resolves"', () => {
3364
+ const { code, rules, output } = run(
3365
+ `import { useBreakpoint } from 'basalt-ui'\nexport const x = useBreakpoint\n`,
3366
+ )
3367
+ expect(code).toBe(1)
3368
+ expect(rules).toContain('deprecated-export')
3369
+ expect(output).toContain('was removed in 1.34.0')
3370
+ expect(output).not.toContain('still resolves')
3371
+ })
3372
+
3373
+ // The row no longer says `fix: false`; `removed` alone must suppress the rewrite, because a
3374
+ // removed row's replacement is prose (`useSizeClass() for shell chrome; …`), not a name.
3375
+ it('never autofixes a removed row', () => {
3376
+ const source = `import { useBreakpoint } from 'basalt-ui'\nexport const x = useBreakpoint\n`
3377
+ writeFileSync(resolve(dir, 'removed-fix.tsx'), source)
3378
+ Bun.spawnSync([OXLINT_BIN, '-c', '.oxlintrc.json', '--fix', 'removed-fix.tsx'], { cwd: dir })
3379
+ expect(readFileSync(resolve(dir, 'removed-fix.tsx'), 'utf8')).toBe(source)
3380
+ })
3381
+ })
3362
3382
 
3363
3383
  // ── forms-field-key ──────────────────────────────────────────────────────────
3364
3384
 
@@ -3574,6 +3594,23 @@ describe('basalt/raw-breakpoint', () => {
3574
3594
  ).not.toContain('raw-breakpoint')
3575
3595
  })
3576
3596
 
3597
+ it('does NOT flag CONTAINER_KEYS computed keys (named, aliased, namespace)', () => {
3598
+ const keyed = (imp: string, key: string) =>
3599
+ run(
3600
+ `import { SimpleGrid } from '@mantine/core'\n${imp}\n` +
3601
+ `export const C = () => <SimpleGrid type="container" cols={{ base: 1, [${key}.regular]: 2, [${key}.wide]: 3 }} />\n`,
3602
+ ).rules
3603
+ expect(
3604
+ keyed(`import { CONTAINER_KEYS } from 'basalt-ui/tokens'`, 'CONTAINER_KEYS'),
3605
+ ).not.toContain('raw-breakpoint')
3606
+ expect(keyed(`import { CONTAINER_KEYS as CQ } from 'basalt-ui/tokens'`, 'CQ')).not.toContain(
3607
+ 'raw-breakpoint',
3608
+ )
3609
+ expect(
3610
+ keyed(`import * as tokens from 'basalt-ui/tokens'`, 'tokens.CONTAINER_KEYS'),
3611
+ ).not.toContain('raw-breakpoint')
3612
+ })
3613
+
3577
3614
  it('does NOT flag a lone `base` under type="container"', () => {
3578
3615
  expect(grid(`<SimpleGrid type="container" cols={{ base: 2 }} />`).rules).not.toContain(
3579
3616
  'raw-breakpoint',
@@ -3997,16 +4034,39 @@ describe('DEPRECATED_EXPORTS', () => {
3997
4034
  }
3998
4035
  ).version
3999
4036
 
4000
- it('carries a replacement and a removeIn at least one minor out on every row', () => {
4001
- const [major, minor] = pkgVersion.split('.').map(Number)
4002
- const floor = `${major}.${(minor as number) + 1}.0`
4037
+ const [major, minor] = pkgVersion.split('.').map(Number)
4038
+ const floor = `${major}.${(minor as number) + 1}.0`
4039
+ const surface = JSON.parse(
4040
+ readFileSync(resolve(import.meta.dirname, '..', 'scripts', 'export-surface.json'), 'utf8'),
4041
+ ) as Record<string, string[]>
4042
+ const shipped = (row: (typeof DEPRECATED_EXPORTS)[number]) =>
4043
+ surface[row.subpath === 'basalt-ui' ? '.' : row.subpath.replace('basalt-ui', '.')]?.includes(
4044
+ row.name,
4045
+ ) === true
4046
+
4047
+ it('carries a replacement and a well-formed removeIn on every row', () => {
4003
4048
  for (const row of DEPRECATED_EXPORTS) {
4004
4049
  expect([row.name, row.replacement.length > 0]).toEqual([row.name, true])
4005
4050
  expect([row.name, /^\d+\.\d+\.\d+$/.test(row.removeIn)]).toEqual([row.name, true])
4051
+ }
4052
+ })
4053
+
4054
+ // A live row still ships, so its removal is still ahead: at least the next minor.
4055
+ it('dates every live row at least one minor out', () => {
4056
+ for (const row of DEPRECATED_EXPORTS.filter((r) => r.removed !== true)) {
4006
4057
  expect([row.name, compareSemver(row.removeIn, floor) >= 0]).toEqual([row.name, true])
4007
4058
  }
4008
4059
  })
4009
4060
 
4061
+ // A removed row is kept past the removal only for its message: the export must really be gone,
4062
+ // and the removing minor is the next one at the latest — never a date still ahead.
4063
+ it('pins every removed row to an export that no longer ships', () => {
4064
+ for (const row of DEPRECATED_EXPORTS.filter((r) => r.removed === true)) {
4065
+ expect([row.name, compareSemver(row.removeIn, floor) <= 0]).toEqual([row.name, true])
4066
+ if (row.prop === undefined) expect([row.name, shipped(row)]).toEqual([row.name, false])
4067
+ }
4068
+ })
4069
+
4010
4070
  it('names a real published subpath on every row', () => {
4011
4071
  const exports = Object.keys(
4012
4072
  (
@@ -4064,7 +4124,9 @@ describe('DEPRECATED_EXPORTS', () => {
4064
4124
  describe('the `Ships:` line above each rule', () => {
4065
4125
  const source = readFileSync(resolve(import.meta.dirname, 'oxlint-plugin.js'), 'utf8')
4066
4126
  const lines = source.split('\n')
4067
- const shipped = JSON.parse(readFileSync(resolve(import.meta.dirname, 'oxlint.json'), 'utf8')) as {
4127
+ const shipped = JSON.parse(
4128
+ readFileSync(resolve(import.meta.dirname, 'oxlint-basalt.json'), 'utf8'),
4129
+ ) as {
4068
4130
  rules: Record<string, unknown>
4069
4131
  }
4070
4132
  // The registry block maps rule id → the `const` implementing it.
@@ -4077,7 +4139,7 @@ describe('the `Ships:` line above each rule', () => {
4077
4139
  })
4078
4140
 
4079
4141
  for (const { id, binding } of registry) {
4080
- it(`${id}: the claim matches oxlint.json`, () => {
4142
+ it(`${id}: the claim matches oxlint-basalt.json`, () => {
4081
4143
  const at = lines.indexOf(`const ${binding} = {`)
4082
4144
  expect([id, at]).not.toEqual([id, -1])
4083
4145
  const claim = /^\/\/ Ships: (.+)$/.exec(lines[at - 1] as string)?.[1]
@@ -4102,3 +4164,29 @@ describe('the `Ships:` line above each rule', () => {
4102
4164
  })
4103
4165
  }
4104
4166
  })
4167
+
4168
+ // emailgw r4b: wiring the full preset on a repo with history forced unrelated jsx-a11y/unicorn
4169
+ // errors before a single basalt/* rule could land. The guards-only preset is the guard lane alone,
4170
+ // and the full preset extends it, so every basalt/* level is stated in exactly one file.
4171
+ describe('configs/oxlint-basalt.json — the guards-only preset', () => {
4172
+ const read = (file: string) =>
4173
+ JSON.parse(readFileSync(resolve(import.meta.dirname, file), 'utf8')) as Record<string, unknown>
4174
+ const guards = read('oxlint-basalt.json')
4175
+ const full = read('oxlint.json')
4176
+
4177
+ it('carries the plugin and basalt/* rules, nothing from the generic preset', () => {
4178
+ expect(Object.keys(guards).toSorted()).toEqual(['jsPlugins', 'rules'])
4179
+ expect(guards['jsPlugins']).toEqual(['./oxlint-plugin.js'])
4180
+ const ids = Object.keys(guards['rules'] as object)
4181
+ expect(ids.filter((id) => !id.startsWith('basalt/'))).toEqual([])
4182
+ expect(ids.length).toBeGreaterThan(0)
4183
+ })
4184
+
4185
+ it('is extended by the full preset, which states no basalt/* level of its own', () => {
4186
+ expect(full['extends']).toEqual(['./oxlint-basalt.json'])
4187
+ expect(full['jsPlugins']).toBeUndefined()
4188
+ expect(Object.keys(full['rules'] as object).filter((id) => id.startsWith('basalt/'))).toEqual(
4189
+ [],
4190
+ )
4191
+ })
4192
+ })
@@ -1,6 +1,6 @@
1
1
  {
2
+ "extends": ["./oxlint-basalt.json"],
2
3
  "plugins": ["react", "typescript", "import", "unicorn", "jsx-a11y", "promise", "oxc"],
3
- "jsPlugins": ["./oxlint-plugin.js"],
4
4
  "categories": {
5
5
  "correctness": "error",
6
6
  "suspicious": "warn"
@@ -22,35 +22,7 @@
22
22
  {
23
23
  "allow": ["__APP_VERSION__"]
24
24
  }
25
- ],
26
- "basalt/no-raw-font-size": "error",
27
- "basalt/raw-size-literal": "error",
28
- "basalt/card-inset": "error",
29
- "basalt/chart-in-raw-surface": "error",
30
- "basalt/hand-rolled-plot": "error",
31
- "basalt/chart-legend-literal": "error",
32
- "basalt/shadow-basalt-export": "warn",
33
- "basalt/hand-rolled-shell": "error",
34
- "basalt/raw-scroll-container": "error",
35
- "basalt/hand-rolled-filter": "error",
36
- "basalt/control-outside-home": "error",
37
- "basalt/bound-control-outside-home": "error",
38
- "basalt/control-size-literal": "error",
39
- "basalt/page-bar-budget": "error",
40
- "basalt/in-body-page-title": "error",
41
- "basalt/responsive-twin": "error",
42
- "basalt/search-literal-link": "error",
43
- "basalt/use-search-from-literal": "error",
44
- "basalt/provider-above-router": "error",
45
- "basalt/query-fn-unwrap": "error",
46
- "basalt/deprecated-export": "warn",
47
- "basalt/forms-field-key": "error",
48
- "basalt/visx-boundary": "error",
49
- "basalt/visx-tooltip": "error",
50
- "basalt/agent-resume-guard": "error",
51
- "basalt/agent-no-raw-usechat": "error",
52
- "basalt/ai-sdk-major": "error",
53
- "basalt/raw-breakpoint": "error"
25
+ ]
54
26
  },
55
27
  "overrides": [
56
28
  {
@@ -1 +1 @@
1
- {"version":3,"file":"check-theme.d.ts","sourceRoot":"","sources":["../../src/cli/check-theme.ts"],"names":[],"mappings":"AA8BA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,aAAa,GAAE,MAAsB,EACrC,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,MAAM,CAuKR"}
1
+ {"version":3,"file":"check-theme.d.ts","sourceRoot":"","sources":["../../src/cli/check-theme.ts"],"names":[],"mappings":"AA+EA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,aAAa,GAAE,MAAsB,EACrC,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,MAAM,CA6IR"}