basalt-ui 2.0.3 → 2.0.5
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/CHANGELOG.md +15 -0
- package/MIGRATING.md +31 -12
- package/dist/cli/doctor-upgrade.d.ts +11 -0
- package/dist/cli/doctor-upgrade.d.ts.map +1 -1
- package/dist/cli/doctor-upgrade.js +59 -32
- package/dist/cli/doctor.d.ts +2 -2
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +19 -36
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +27 -55
- package/dist/content/highlighter.d.ts.map +1 -1
- package/dist/content/highlighter.js +14 -2
- package/dist/table/data-table.d.ts.map +1 -1
- package/dist/table/data-table.js +6 -2
- package/dist/table/data-table.module.css +43 -0
- package/dist/table/data-table.module.css.d.ts +3 -0
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/cli/doctor-upgrade.ts +88 -37
- package/src/cli/doctor.ts +23 -45
- package/src/cli/index.ts +35 -66
- package/src/content/highlighter.ts +18 -2
- package/src/table/data-table.module.css +43 -0
- package/src/table/data-table.module.css.d.ts +3 -0
- package/src/table/data-table.tsx +10 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/table/data-table.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/table/data-table.tsx"],"names":[],"mappings":"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"}
|
package/dist/table/data-table.js
CHANGED
|
@@ -588,7 +588,11 @@ function BasaltDataTable(props) {
|
|
|
588
588
|
const tableNode = /* @__PURE__ */ jsxs(
|
|
589
589
|
Table,
|
|
590
590
|
{
|
|
591
|
-
className: cx(
|
|
591
|
+
className: cx(
|
|
592
|
+
classes.table,
|
|
593
|
+
pageStickyHeader && !contained && classes.pageSticky,
|
|
594
|
+
classNames?.table
|
|
595
|
+
),
|
|
592
596
|
...striped !== void 0 && { striped },
|
|
593
597
|
...highlightOnHover !== void 0 && { highlightOnHover },
|
|
594
598
|
...stickyHeader !== void 0 && { stickyHeader },
|
|
@@ -601,7 +605,7 @@ function BasaltDataTable(props) {
|
|
|
601
605
|
withTableBorder,
|
|
602
606
|
children: [
|
|
603
607
|
/* @__PURE__ */ jsx(Table.Thead, { children: headerGroups.map((headerGroup) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
604
|
-
hasFolded && /* @__PURE__ */ jsx(Table.Th, { className: classes.foldToggleCell, "
|
|
608
|
+
hasFolded && /* @__PURE__ */ jsx(Table.Th, { className: classes.foldToggleCell, children: /* @__PURE__ */ jsx("span", { className: classes.srOnly, children: "Details" }) }),
|
|
605
609
|
headerGroup.headers.map((header) => {
|
|
606
610
|
const canSort = sortingEnabled && header.column.getCanSort();
|
|
607
611
|
const sorted = header.column.getIsSorted();
|
|
@@ -63,6 +63,49 @@
|
|
|
63
63
|
overflow-x: auto;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/*
|
|
67
|
+
* A page-scrolled sticky header INSIDE the shell seals the strip above it.
|
|
68
|
+
*
|
|
69
|
+
* `AppShell.Main` is the scrollport and carries block padding (`app-main.module.css`: `stack-md`,
|
|
70
|
+
* one rung down to `stack-sm` from `sm` up). A sticky `<thead>` resolves against the scrollport's
|
|
71
|
+
* CONTENT edge, so at `top: 0` it parked that padding below the band and every body row scrolled
|
|
72
|
+
* through the gap. A negative offset equal to the padding moves the stick line out to the band's
|
|
73
|
+
* edge, flush. The two media/token pairs below mirror `.main` there — the layout suite
|
|
74
|
+
* (`data-table.layout.test.ts`, invariant 8) fails on drift. A consumer `stickyHeaderOffset` is an
|
|
75
|
+
* inline `--table-sticky-header-offset` on the table and beats this class, so it still wins.
|
|
76
|
+
* Outside a shell no `.mantine-AppShell-main` ancestor matches and the offset stays 0.
|
|
77
|
+
*/
|
|
78
|
+
:global(.mantine-AppShell-main) .pageSticky {
|
|
79
|
+
--table-sticky-header-offset: calc(-1 * var(--vx-space-stack-md));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* theme-allow raw-media-query — mirrors app-main.module.css's own `sm` switch for Main's block padding; invariant 8 in data-table.layout.test.ts fails on drift */
|
|
83
|
+
@media (min-width: 52.5em) {
|
|
84
|
+
:global(.mantine-AppShell-main) .pageSticky {
|
|
85
|
+
--table-sticky-header-offset: calc(-1 * var(--vx-space-stack-sm));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
* A Badge cell keeps its label. Mantine's Badge label is `overflow: hidden; text-overflow:
|
|
91
|
+
* ellipsis`, which gives the badge a min-content of ~0, so an auto-layout column holding only
|
|
92
|
+
* badges was free to shrink under its neighbours (`WORKING` → `WOR…` at 1280px). `max-content`
|
|
93
|
+
* as the floor makes the status column the widest thing a short enum ever needs.
|
|
94
|
+
*/
|
|
95
|
+
.table :global(.mantine-Badge-root) {
|
|
96
|
+
min-width: max-content;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Visually hidden, still announced — the fold toggle column's header has no visible label. */
|
|
100
|
+
.srOnly {
|
|
101
|
+
position: absolute;
|
|
102
|
+
width: 1px;
|
|
103
|
+
height: 1px;
|
|
104
|
+
overflow: hidden;
|
|
105
|
+
clip-path: inset(50%);
|
|
106
|
+
white-space: nowrap;
|
|
107
|
+
}
|
|
108
|
+
|
|
66
109
|
/*
|
|
67
110
|
* The selection column's hit area is the WHOLE cell (`docs/CONTROLS-SPEC.md` §2): the
|
|
68
111
|
* cell is the positioning box and the wrapping <label>'s ::after stretches over it, so a tap
|
|
@@ -16,7 +16,10 @@ declare const classes: {
|
|
|
16
16
|
readonly foldToggle: string
|
|
17
17
|
readonly foldToggleCell: string
|
|
18
18
|
readonly foldWrapper: string
|
|
19
|
+
readonly pageSticky: string
|
|
19
20
|
readonly selectCell: string
|
|
20
21
|
readonly selectHit: string
|
|
22
|
+
readonly srOnly: string
|
|
23
|
+
readonly table: string
|
|
21
24
|
}
|
|
22
25
|
export default classes
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v2.0.
|
|
1
|
+
# basalt-ui v2.0.5
|
|
2
2
|
# Opinionated framework for Mantine-based React apps — theme, app shell, TanStack Charts, toolchain presets
|
|
3
3
|
#
|
|
4
4
|
# Entry points: use the exact import specifier below; do not guess.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# A subpath's `Install:` line is its required peers; `OptionalPeers:` are import()-only, install on use.
|
|
14
14
|
|
|
15
15
|
Package: basalt-ui
|
|
16
|
-
Version: 2.0.
|
|
16
|
+
Version: 2.0.5
|
|
17
17
|
|
|
18
18
|
## basalt-ui
|
|
19
19
|
Import: import { ... } from 'basalt-ui'
|
package/package.json
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* `doctor`'s 2.0 strictness and upgrade checks. Each returns null (pass), `{ fail }` (the problem
|
|
3
3
|
* plus its fix) or `{ skip }` (the check could not run: a check that cannot run is not a pass).
|
|
4
4
|
*/
|
|
5
|
-
import { existsSync,
|
|
5
|
+
import { existsSync, writeFileSync } from 'node:fs'
|
|
6
6
|
import { createRequire } from 'node:module'
|
|
7
7
|
import { dirname, relative, resolve } from 'node:path'
|
|
8
8
|
|
|
9
9
|
import { BASALT_CONFIG_KEYS, RETIRED_CONFIG_KEYS } from './config'
|
|
10
10
|
import type { BasaltConfig } from './config'
|
|
11
|
-
import { parseJsonc, readIfExists, scannableFiles } from './index'
|
|
11
|
+
import { parseJsonc, readIfExists, readPackageJson, scannableFiles } from './index'
|
|
12
12
|
import type { BasaltInstall } from './index'
|
|
13
13
|
|
|
14
14
|
export type Check = { fail: string } | { skip: string } | null
|
|
@@ -22,6 +22,19 @@ const guarded = (id: string, run: () => Check): Check => {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** A check that reads the resolved install: skips when basalt-ui does not resolve. */
|
|
26
|
+
const withInstall = (
|
|
27
|
+
id: string,
|
|
28
|
+
install: BasaltInstall,
|
|
29
|
+
reads: string,
|
|
30
|
+
run: (dir: string) => Check,
|
|
31
|
+
): Check => {
|
|
32
|
+
const { dir } = install
|
|
33
|
+
return dir === null
|
|
34
|
+
? { skip: `${id}: basalt-ui does not resolve, so its ${reads} cannot be read.` }
|
|
35
|
+
: guarded(id, () => run(dir))
|
|
36
|
+
}
|
|
37
|
+
|
|
25
38
|
const TSCONFIG_PRESET = /(?:^|\/)basalt-ui\/configs\/tsconfig\.(?:base|react-app)\.json$/
|
|
26
39
|
const TSCONFIG_PRESET_ID = 'basalt-ui/configs/tsconfig.react-app.json'
|
|
27
40
|
const TSCONFIG_FIX = `"extends": "${TSCONFIG_PRESET_ID}" (tsconfig.base.json for a package without a DOM)`
|
|
@@ -148,10 +161,7 @@ function basaltRuleIds(file: string, seen = new Set<string>()): string[] {
|
|
|
148
161
|
/** `retired-lint-rules`: `basalt/<id>` entries the installed plugin no longer registers. */
|
|
149
162
|
export function retiredLintRulesCheck(cwd: string, install: BasaltInstall): Check {
|
|
150
163
|
const id = 'retired-lint-rules'
|
|
151
|
-
|
|
152
|
-
if (dir === null)
|
|
153
|
-
return { skip: `${id}: basalt-ui does not resolve, so its plugin cannot be read.` }
|
|
154
|
-
return guarded(id, () => {
|
|
164
|
+
return withInstall(id, install, 'plugin', (dir) => {
|
|
155
165
|
const ids = [...new Set(basaltRuleIds(resolve(cwd, '.oxlintrc.json')))]
|
|
156
166
|
if (ids.length === 0) return null
|
|
157
167
|
const pluginPath = resolve(dir, 'configs/oxlint-plugin.js')
|
|
@@ -215,6 +225,16 @@ function basaltImports(src: string): [string, number][] {
|
|
|
215
225
|
.map((m) => [m[2] as string, code.slice(0, m.index + m[0].length).split('\n').length])
|
|
216
226
|
}
|
|
217
227
|
|
|
228
|
+
/** `[subpath, file, line]` per `basalt-ui/<subpath>` import in the app's source files. */
|
|
229
|
+
const appImports = (cwd: string, cfg: BasaltConfig): [string, string, number][] =>
|
|
230
|
+
scannableFiles(cwd, cfg)
|
|
231
|
+
.filter((f) => /\.(?:[cm]?[jt]sx?|vue|astro)$/.test(f))
|
|
232
|
+
.flatMap((rel) =>
|
|
233
|
+
basaltImports(readIfExists(resolve(cwd, rel)) ?? '').map(
|
|
234
|
+
([sub, line]): [string, string, number] => [sub, rel, line],
|
|
235
|
+
),
|
|
236
|
+
)
|
|
237
|
+
|
|
218
238
|
/** `dropped-subpaths`: `basalt-ui/<subpath>` imports the installed `exports` map does not have. */
|
|
219
239
|
export function droppedSubpathsCheck(
|
|
220
240
|
cwd: string,
|
|
@@ -222,28 +242,20 @@ export function droppedSubpathsCheck(
|
|
|
222
242
|
install: BasaltInstall,
|
|
223
243
|
): Check {
|
|
224
244
|
const id = 'dropped-subpaths'
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const pkg = JSON.parse(readFileSync(resolve(dir, 'package.json'), 'utf8')) as {
|
|
230
|
-
exports?: Record<string, unknown>
|
|
231
|
-
}
|
|
245
|
+
return withInstall(id, install, 'exports', (dir) => {
|
|
246
|
+
const pkg = readPackageJson<{ exports?: Record<string, unknown> }>(dir)
|
|
247
|
+
if (pkg === null) throw new Error(`${dir}/package.json is unreadable`)
|
|
248
|
+
const exportsMap = pkg.exports
|
|
232
249
|
// No `exports` field means nothing restricts the deep imports.
|
|
233
|
-
if (
|
|
234
|
-
const keys = Object.keys(
|
|
250
|
+
if (exportsMap === undefined) return null
|
|
251
|
+
const keys = Object.keys(exportsMap)
|
|
235
252
|
const has = (sub: string): boolean =>
|
|
236
253
|
keys.some(
|
|
237
254
|
(k) => k === `./${sub}` || (k.endsWith('*') && `./${sub}`.startsWith(k.slice(0, -1))),
|
|
238
255
|
)
|
|
239
|
-
const hits
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
)) {
|
|
243
|
-
for (const [sub, line] of basaltImports(readIfExists(resolve(cwd, rel)) ?? '')) {
|
|
244
|
-
if (!has(sub)) hits.push(`${rel}:${line} imports basalt-ui/${sub}`)
|
|
245
|
-
}
|
|
246
|
-
}
|
|
256
|
+
const hits = appImports(cwd, cfg)
|
|
257
|
+
.filter(([sub]) => !has(sub))
|
|
258
|
+
.map(([sub, rel, line]) => `${rel}:${line} imports basalt-ui/${sub}`)
|
|
247
259
|
if (hits.length === 0) return null
|
|
248
260
|
const more = hits.length > 10 ? ` (+${hits.length - 10} more)` : ''
|
|
249
261
|
return {
|
|
@@ -446,8 +458,7 @@ export function appWiringCheck(cwd: string): Check {
|
|
|
446
458
|
*/
|
|
447
459
|
export function unknownConfigKeysCheck(cwd: string): Check {
|
|
448
460
|
return guarded('config-keys', () => {
|
|
449
|
-
const
|
|
450
|
-
const block = raw === null ? null : (JSON.parse(raw) as { basalt?: unknown }).basalt
|
|
461
|
+
const block = readPackageJson<{ basalt?: unknown }>(cwd)?.basalt
|
|
451
462
|
if (typeof block !== 'object' || block === null || Array.isArray(block)) return null
|
|
452
463
|
const known = new Set<string>(BASALT_CONFIG_KEYS)
|
|
453
464
|
const unknown = Object.keys(block).filter((k) => !known.has(k))
|
|
@@ -461,13 +472,18 @@ export function unknownConfigKeysCheck(cwd: string): Check {
|
|
|
461
472
|
})
|
|
462
473
|
}
|
|
463
474
|
|
|
475
|
+
/** The `peerDependencies` ranges declared by the package installed at `dir`. */
|
|
476
|
+
function peerRanges(dir: string): Record<string, string> {
|
|
477
|
+
return readPackageJson<{ peerDependencies?: Record<string, string> }>(dir)?.peerDependencies ?? {}
|
|
478
|
+
}
|
|
479
|
+
|
|
464
480
|
const EXACT_VERSION = /^\d+\.\d+\.\d+$/
|
|
465
481
|
|
|
466
482
|
/** `node_modules/<pkg>/package.json`'s version, searching `cwd` then every ancestor. */
|
|
467
483
|
function installedVersion(cwd: string, pkg: string): string | null {
|
|
468
484
|
for (let dir = cwd; ; dir = dirname(dir)) {
|
|
469
|
-
const
|
|
470
|
-
if (
|
|
485
|
+
const manifest = readPackageJson<{ version?: string }>(resolve(dir, 'node_modules', pkg))
|
|
486
|
+
if (manifest !== null) return manifest.version ?? null
|
|
471
487
|
if (dirname(dir) === dir) return null
|
|
472
488
|
}
|
|
473
489
|
}
|
|
@@ -479,16 +495,8 @@ function installedVersion(cwd: string, pkg: string): string | null {
|
|
|
479
495
|
*/
|
|
480
496
|
export function exactPeersCheck(cwd: string, install: BasaltInstall): Check {
|
|
481
497
|
const id = 'exact-peers'
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
const dir = install.dir
|
|
485
|
-
return guarded(id, () => {
|
|
486
|
-
const raw = readIfExists(resolve(dir, 'package.json'))
|
|
487
|
-
const peers =
|
|
488
|
-
(raw === null
|
|
489
|
-
? {}
|
|
490
|
-
: (JSON.parse(raw) as { peerDependencies?: Record<string, string> }).peerDependencies) ?? {}
|
|
491
|
-
const off = Object.entries(peers)
|
|
498
|
+
return withInstall(id, install, 'peers', (dir) => {
|
|
499
|
+
const off = Object.entries(peerRanges(dir))
|
|
492
500
|
.filter(([, range]) => EXACT_VERSION.test(range))
|
|
493
501
|
.flatMap(([pkg, pin]) => {
|
|
494
502
|
const have = installedVersion(cwd, pkg)
|
|
@@ -502,3 +510,46 @@ export function exactPeersCheck(cwd: string, install: BasaltInstall): Check {
|
|
|
502
510
|
}
|
|
503
511
|
})
|
|
504
512
|
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* The peers a subpath needs installed: V2-SPEC § 1's subpath-required class plus `./content`'s
|
|
516
|
+
* shiki trio, which a bundler cannot resolve without them (argo friction row 15). The test pins it
|
|
517
|
+
* to `package.json` and `surfaces.ts`.
|
|
518
|
+
*/
|
|
519
|
+
export const SUBPATH_REQUIRED_PEERS: Readonly<Record<string, readonly string[]>> = {
|
|
520
|
+
agent: ['ai', '@ai-sdk/provider', 'motion'],
|
|
521
|
+
charts: ['@tanstack/charts', 'd3-scale'],
|
|
522
|
+
commands: ['@tanstack/react-hotkeys'],
|
|
523
|
+
content: ['react-markdown', 'shiki', '@shikijs/langs', '@shikijs/themes'],
|
|
524
|
+
'controls-dates': ['@mantine/dates', 'dayjs'],
|
|
525
|
+
forms: ['@mantine/form'],
|
|
526
|
+
table: ['@tanstack/react-table'],
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* `subpath-peers`: every `basalt-ui/<subpath>` the app imports has its required peers installed. A
|
|
531
|
+
* missing one still builds, then throws "Could not resolve" when the chunk loads.
|
|
532
|
+
*/
|
|
533
|
+
export function subpathPeersCheck(cwd: string, cfg: BasaltConfig, install: BasaltInstall): Check {
|
|
534
|
+
const id = 'subpath-peers'
|
|
535
|
+
return withInstall(id, install, 'peers', (dir) => {
|
|
536
|
+
const missing = new Map<string, string[]>()
|
|
537
|
+
for (const [sub, file] of new Map(
|
|
538
|
+
appImports(cwd, cfg)
|
|
539
|
+
.toReversed()
|
|
540
|
+
.map(([s, f]) => [s, f]),
|
|
541
|
+
)) {
|
|
542
|
+
for (const peer of SUBPATH_REQUIRED_PEERS[sub] ?? []) {
|
|
543
|
+
if (installedVersion(cwd, peer) !== null) continue
|
|
544
|
+
missing.set(peer, [...(missing.get(peer) ?? []), `basalt-ui/${sub} (${file})`])
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (missing.size === 0) return null
|
|
548
|
+
const ranges = peerRanges(dir)
|
|
549
|
+
const named = [...missing].map(([peer, by]) => `${peer} for ${by.join(', ')}`)
|
|
550
|
+
const add = [...missing.keys()].map((peer) => (ranges[peer] ? `${peer}@${ranges[peer]}` : peer))
|
|
551
|
+
return {
|
|
552
|
+
fail: `${id}: peers a used basalt-ui subpath requires are not installed: ${named.join('; ')}. Fix: \`bun add ${add.join(' ')}\`.`,
|
|
553
|
+
}
|
|
554
|
+
})
|
|
555
|
+
}
|
package/src/cli/doctor.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { existsSync } from 'node:fs'
|
|
7
7
|
import { relative, resolve } from 'node:path'
|
|
8
8
|
|
|
9
|
-
import type { BasaltConfig } from './config'
|
|
10
9
|
import {
|
|
11
10
|
AGENTS_MD,
|
|
12
11
|
LEGACY_BLOCK_HOST,
|
|
@@ -26,6 +25,7 @@ import {
|
|
|
26
25
|
readBasaltConfig,
|
|
27
26
|
readIfExists,
|
|
28
27
|
readManifest,
|
|
28
|
+
readPackageJson,
|
|
29
29
|
resolveAppDir,
|
|
30
30
|
resolveProjectDir,
|
|
31
31
|
ROUTER_SEED_DESTS,
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
droppedSubpathsCheck,
|
|
41
41
|
exactPeersCheck,
|
|
42
42
|
retiredLintRulesCheck,
|
|
43
|
+
subpathPeersCheck,
|
|
43
44
|
tsconfigBaseCheck,
|
|
44
45
|
unknownConfigKeysCheck,
|
|
45
46
|
} from './doctor-upgrade'
|
|
@@ -85,32 +86,13 @@ type AiMajorField = (typeof AI_MAJOR_FIELDS)[number]
|
|
|
85
86
|
|
|
86
87
|
/** The `ai` major per dependency field of THIS package.json (not walked across workspaces). */
|
|
87
88
|
function aiMajorsAt(dir: string): Partial<Record<AiMajorField, number>> {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
for (const field of AI_MAJOR_FIELDS) {
|
|
94
|
-
const major = majorOf(pkg[field]?.['ai'])
|
|
95
|
-
if (major !== null) out[field] = major
|
|
96
|
-
}
|
|
97
|
-
return out
|
|
98
|
-
} catch {
|
|
99
|
-
return {}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** `basalt.aiMajorSkewReason` as a validated reason, plus whether the key was present but invalid. */
|
|
104
|
-
function resolveAiMajorSkewReason(cfg: BasaltConfig): {
|
|
105
|
-
reason: string | null
|
|
106
|
-
presentButInvalid: boolean
|
|
107
|
-
} {
|
|
108
|
-
const raw = cfg.aiMajorSkewReason
|
|
109
|
-
if (raw === undefined) return { reason: null, presentButInvalid: false }
|
|
110
|
-
if (typeof raw === 'string' && raw.trim().length > 0) {
|
|
111
|
-
return { reason: raw, presentButInvalid: false }
|
|
89
|
+
const pkg = readPackageJson<Partial<Record<AiMajorField, Record<string, string>>>>(dir) ?? {}
|
|
90
|
+
const out: Partial<Record<AiMajorField, number>> = {}
|
|
91
|
+
for (const field of AI_MAJOR_FIELDS) {
|
|
92
|
+
const major = majorOf(pkg[field]?.['ai'])
|
|
93
|
+
if (major !== null) out[field] = major
|
|
112
94
|
}
|
|
113
|
-
return
|
|
95
|
+
return out
|
|
114
96
|
}
|
|
115
97
|
|
|
116
98
|
/**
|
|
@@ -124,8 +106,8 @@ function resolveAiMajorSkewReason(cfg: BasaltConfig): {
|
|
|
124
106
|
* 4. `oxlint-preset`: `.oxlintrc.json` extends the shipped preset AND that path resolves.
|
|
125
107
|
* 7. `ai-major-parity`: the `ai` major agrees across this package.json's dependency fields
|
|
126
108
|
* (exempt via `basalt.aiMajorSkewReason`; a stale reason warns).
|
|
127
|
-
* 8-
|
|
128
|
-
* `config-keys` (./doctor-upgrade);
|
|
109
|
+
* 8-14. `tsconfig-base`, `retired-lint-rules`, `dropped-subpaths`, `app-wiring`, `exact-peers`,
|
|
110
|
+
* `subpath-peers`, `config-keys` (./doctor-upgrade);
|
|
129
111
|
* a check that cannot run is SKIPPED and exits non-zero.
|
|
130
112
|
*
|
|
131
113
|
* Warning (non-fatal):
|
|
@@ -153,21 +135,10 @@ export function doctor(invocationCwd: string = process.cwd(), flags: string[] =
|
|
|
153
135
|
const result: DoctorResult = { hardFailures: 0, warnings: 0, skipped: 0 }
|
|
154
136
|
const lines: string[] = [`\nbasalt-ui doctor — ${cwd}\n`]
|
|
155
137
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
lines.push(` ⚠ ${msg}`)
|
|
161
|
-
result.warnings++
|
|
162
|
-
}
|
|
163
|
-
function fail(msg: string): void {
|
|
164
|
-
lines.push(` ✖ ${msg}`)
|
|
165
|
-
result.hardFailures++
|
|
166
|
-
}
|
|
167
|
-
function skip(msg: string): void {
|
|
168
|
-
lines.push(` ? SKIPPED ${msg}`)
|
|
169
|
-
result.skipped++
|
|
170
|
-
}
|
|
138
|
+
const pass = (msg: string): number => lines.push(` ✓ ${msg}`)
|
|
139
|
+
const warn = (msg: string): number => lines.push(` ⚠ ${msg}`) && result.warnings++
|
|
140
|
+
const fail = (msg: string): number => lines.push(` ✖ ${msg}`) && result.hardFailures++
|
|
141
|
+
const skip = (msg: string): number => lines.push(` ? SKIPPED ${msg}`) && result.skipped++
|
|
171
142
|
|
|
172
143
|
if (project.relocatedFrom !== null) {
|
|
173
144
|
lines.push(` → BASALT_CWD relocated from ${project.relocatedFrom} to ${cwd}.\n`)
|
|
@@ -368,8 +339,11 @@ export function doctor(invocationCwd: string = process.cwd(), flags: string[] =
|
|
|
368
339
|
const aiEntries = AI_MAJOR_FIELDS.filter((field) => aiMajors[field] !== undefined).map(
|
|
369
340
|
(field) => ({ field, major: aiMajors[field] as number }),
|
|
370
341
|
)
|
|
371
|
-
|
|
372
|
-
|
|
342
|
+
// `basalt.aiMajorSkewReason`: a non-blank string exempts a skew; any other present value is invalid.
|
|
343
|
+
const rawSkewReason = cfg.aiMajorSkewReason
|
|
344
|
+
const aiMajorSkewReason =
|
|
345
|
+
typeof rawSkewReason === 'string' && rawSkewReason.trim().length > 0 ? rawSkewReason : null
|
|
346
|
+
const aiMajorSkewReasonInvalid = aiMajorSkewReason === null && rawSkewReason !== undefined
|
|
373
347
|
if (aiEntries.length > 0) {
|
|
374
348
|
const distinctMajors = new Set(aiEntries.map((entry) => entry.major))
|
|
375
349
|
if (distinctMajors.size > 1) {
|
|
@@ -428,6 +402,10 @@ export function doctor(invocationCwd: string = process.cwd(), flags: string[] =
|
|
|
428
402
|
appWiringCheck(appDir),
|
|
429
403
|
],
|
|
430
404
|
['exact-peers: installed exact-pinned peers match basalt-ui', exactPeersCheck(cwd, install)],
|
|
405
|
+
[
|
|
406
|
+
'subpath-peers: every imported basalt-ui subpath has its required peers installed',
|
|
407
|
+
subpathPeersCheck(cwd, cfg, install),
|
|
408
|
+
],
|
|
431
409
|
[
|
|
432
410
|
'config-keys: the basalt config block sets only keys basalt-ui reads',
|
|
433
411
|
unknownConfigKeysCheck(cwd),
|
package/src/cli/index.ts
CHANGED
|
@@ -148,23 +148,11 @@ function sanitizeSeverity(cfg: BasaltConfig): BasaltConfig {
|
|
|
148
148
|
/** Does `cwd`'s own `package.json` carry a `basalt` key? — "misconfigured roots" vs "wrong
|
|
149
149
|
* directory", the failure a root-invoked hook hits since 1.29.0's single resolver. Never a walk. */
|
|
150
150
|
export function hasBasaltKey(cwd: string): boolean {
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
return raw !== null && (JSON.parse(raw) as { basalt?: unknown }).basalt !== undefined
|
|
154
|
-
} catch {
|
|
155
|
-
return false
|
|
156
|
-
}
|
|
151
|
+
return readPackageJson<{ basalt?: unknown }>(cwd)?.basalt !== undefined
|
|
157
152
|
}
|
|
158
153
|
|
|
159
154
|
export function readBasaltConfig(cwd: string): BasaltConfig {
|
|
160
|
-
|
|
161
|
-
const pkg = JSON.parse(readFileSync(resolve(cwd, 'package.json'), 'utf8')) as {
|
|
162
|
-
basalt?: BasaltConfig
|
|
163
|
-
}
|
|
164
|
-
return sanitizeSeverity(pkg.basalt ?? {})
|
|
165
|
-
} catch {
|
|
166
|
-
return {}
|
|
167
|
-
}
|
|
155
|
+
return sanitizeSeverity(readPackageJson<{ basalt?: BasaltConfig }>(cwd)?.basalt ?? {})
|
|
168
156
|
}
|
|
169
157
|
|
|
170
158
|
/**
|
|
@@ -237,13 +225,10 @@ const UNRESOLVED_INSTALL: BasaltInstall = { dir: null, version: null, how: null
|
|
|
237
225
|
/** `<dir>/node_modules/basalt-ui` when it holds a readable package.json, else null. */
|
|
238
226
|
function basaltInstallAt(dir: string): { dir: string; version: string | null } | null {
|
|
239
227
|
const installDir = resolve(dir, 'node_modules', 'basalt-ui')
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return { dir: installDir, version: pkg.version ?? null }
|
|
245
|
-
} catch {
|
|
246
|
-
return { dir: installDir, version: null }
|
|
228
|
+
if (readIfExists(resolve(installDir, 'package.json')) === null) return null
|
|
229
|
+
return {
|
|
230
|
+
dir: installDir,
|
|
231
|
+
version: readPackageJson<{ version?: string }>(installDir)?.version ?? null,
|
|
247
232
|
}
|
|
248
233
|
}
|
|
249
234
|
|
|
@@ -500,31 +485,30 @@ export function readIfExists(abs: string): string | null {
|
|
|
500
485
|
}
|
|
501
486
|
}
|
|
502
487
|
|
|
488
|
+
/** `<dir>/package.json` parsed as `T`; null when absent or not JSON. */
|
|
489
|
+
export function readPackageJson<T>(dir: string): T | null {
|
|
490
|
+
const raw = readIfExists(resolve(dir, 'package.json'))
|
|
491
|
+
try {
|
|
492
|
+
return raw === null ? null : (JSON.parse(raw) as T)
|
|
493
|
+
} catch {
|
|
494
|
+
return null
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
503
498
|
/** Read a shipped source asset from the package root; null if the sibling hasn't authored it yet. */
|
|
504
499
|
export function readSource(pkgRoot: string, source: string): string | null {
|
|
505
500
|
return readIfExists(resolve(pkgRoot, source))
|
|
506
501
|
}
|
|
507
502
|
|
|
508
503
|
function readPackageName(cwd: string): string {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (pkg.name && pkg.name.length > 0) return pkg.name
|
|
512
|
-
} catch {
|
|
513
|
-
// fall through to dir name
|
|
514
|
-
}
|
|
504
|
+
const name = readPackageJson<{ name?: string }>(cwd)?.name
|
|
505
|
+
if (name && name.length > 0) return name
|
|
515
506
|
return cwd.split('/').filter(Boolean).pop() ?? 'app'
|
|
516
507
|
}
|
|
517
508
|
|
|
518
509
|
/** The framework's own published version, read from the package root package.json. */
|
|
519
510
|
export function readFrameworkVersion(pkgRoot: string): string {
|
|
520
|
-
|
|
521
|
-
const pkg = JSON.parse(readFileSync(resolve(pkgRoot, 'package.json'), 'utf8')) as {
|
|
522
|
-
version?: string
|
|
523
|
-
}
|
|
524
|
-
return pkg.version ?? '0.0.0'
|
|
525
|
-
} catch {
|
|
526
|
-
return '0.0.0'
|
|
527
|
-
}
|
|
511
|
+
return readPackageJson<{ version?: string }>(pkgRoot)?.version ?? '0.0.0'
|
|
528
512
|
}
|
|
529
513
|
|
|
530
514
|
/**
|
|
@@ -733,20 +717,18 @@ export function resolveAppDir(root: string): AppResolution {
|
|
|
733
717
|
|
|
734
718
|
/** True when `pkgName` appears in the consumer's dependencies, devDependencies, or peerDependencies. */
|
|
735
719
|
function hasDependency(cwd: string, pkgName: string): boolean {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
return false
|
|
749
|
-
}
|
|
720
|
+
const pkg =
|
|
721
|
+
readPackageJson<
|
|
722
|
+
Record<
|
|
723
|
+
'dependencies' | 'devDependencies' | 'peerDependencies',
|
|
724
|
+
Record<string, string> | undefined
|
|
725
|
+
>
|
|
726
|
+
>(cwd)
|
|
727
|
+
return Boolean(
|
|
728
|
+
pkg?.dependencies?.[pkgName] ??
|
|
729
|
+
pkg?.devDependencies?.[pkgName] ??
|
|
730
|
+
pkg?.peerDependencies?.[pkgName],
|
|
731
|
+
)
|
|
750
732
|
}
|
|
751
733
|
|
|
752
734
|
/**
|
|
@@ -1275,14 +1257,8 @@ export function patchPackageJson(
|
|
|
1275
1257
|
): boolean {
|
|
1276
1258
|
const abs = resolve(cwd, 'package.json')
|
|
1277
1259
|
const raw = readIfExists(abs)
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
try {
|
|
1281
|
-
pkg = JSON.parse(raw) as Record<string, unknown>
|
|
1282
|
-
} catch {
|
|
1283
|
-
return false
|
|
1284
|
-
}
|
|
1285
|
-
if (!mutate(pkg)) return false
|
|
1260
|
+
const pkg = readPackageJson<Record<string, unknown>>(cwd)
|
|
1261
|
+
if (raw === null || pkg === null || !mutate(pkg)) return false
|
|
1286
1262
|
const indent = /\n([ \t]+)"/.exec(raw)?.[1] ?? ' '
|
|
1287
1263
|
writeFileSync(abs, JSON.stringify(pkg, null, indent) + (raw.endsWith('\n') ? '\n' : ''))
|
|
1288
1264
|
return true
|
|
@@ -1689,15 +1665,8 @@ function expandWorkspaceGlobs(cwd: string, patterns: readonly string[]): string[
|
|
|
1689
1665
|
* an unrecognized `workspaces` shape.
|
|
1690
1666
|
*/
|
|
1691
1667
|
function collectWorkspacePackages(cwd: string): WorkspaceWalk {
|
|
1692
|
-
const
|
|
1693
|
-
if (
|
|
1694
|
-
|
|
1695
|
-
let parsed: { workspaces?: unknown; name?: string }
|
|
1696
|
-
try {
|
|
1697
|
-
parsed = JSON.parse(raw) as { workspaces?: unknown; name?: string }
|
|
1698
|
-
} catch {
|
|
1699
|
-
return { packages: [], hasWorkspacesField: false }
|
|
1700
|
-
}
|
|
1668
|
+
const parsed = readPackageJson<{ workspaces?: unknown; name?: string }>(cwd)
|
|
1669
|
+
if (parsed === null) return { packages: [], hasWorkspacesField: false }
|
|
1701
1670
|
|
|
1702
1671
|
const patterns = isStringArray(parsed.workspaces)
|
|
1703
1672
|
? parsed.workspaces
|
|
@@ -64,6 +64,18 @@ const LANG_ALIASES: Record<string, string> = {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
let highlighterPromise: Promise<HighlighterCore | null> | null = null
|
|
67
|
+
let warnedMissingPeer = false
|
|
68
|
+
|
|
69
|
+
/** Dev-only, once per process: the highlighter peers did not resolve, so code stays unhighlighted. */
|
|
70
|
+
function warnMissingPeer(error: unknown): void {
|
|
71
|
+
if (warnedMissingPeer || process.env['NODE_ENV'] === 'production') return
|
|
72
|
+
warnedMissingPeer = true
|
|
73
|
+
console.warn(
|
|
74
|
+
'[basalt] CodeBlock: syntax highlighting is off — a peer of basalt-ui/content did not load ' +
|
|
75
|
+
`(${error instanceof Error ? error.message : String(error)}). Code renders unhighlighted. ` +
|
|
76
|
+
'Install them with: bun add shiki @shikijs/langs @shikijs/themes',
|
|
77
|
+
)
|
|
78
|
+
}
|
|
67
79
|
|
|
68
80
|
async function loadHighlighter(): Promise<HighlighterCore | null> {
|
|
69
81
|
const [{ createHighlighterCore }, { createJavaScriptRegexEngine }] = await Promise.all([
|
|
@@ -79,7 +91,10 @@ async function loadHighlighter(): Promise<HighlighterCore | null> {
|
|
|
79
91
|
|
|
80
92
|
/** Module-level singleton — resolves once; every caller shares the same highlighter instance. */
|
|
81
93
|
function getHighlighter(): Promise<HighlighterCore | null> {
|
|
82
|
-
highlighterPromise ??= loadHighlighter().catch(() =>
|
|
94
|
+
highlighterPromise ??= loadHighlighter().catch((error: unknown) => {
|
|
95
|
+
warnMissingPeer(error)
|
|
96
|
+
return null
|
|
97
|
+
})
|
|
83
98
|
return highlighterPromise
|
|
84
99
|
}
|
|
85
100
|
|
|
@@ -91,7 +106,8 @@ async function ensureLanguage(highlighter: HighlighterCore, lang: string): Promi
|
|
|
91
106
|
try {
|
|
92
107
|
await highlighter.loadLanguage(loadLang() as LanguageInput)
|
|
93
108
|
return true
|
|
94
|
-
} catch {
|
|
109
|
+
} catch (error) {
|
|
110
|
+
warnMissingPeer(error)
|
|
95
111
|
return false
|
|
96
112
|
}
|
|
97
113
|
}
|