banhaten 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +139 -73
- package/CONTRIBUTING.md +46 -44
- package/README.md +192 -190
- package/SECURITY.md +15 -15
- package/banhaten.config.example.json +11 -11
- package/docs/design-spacing.md +13 -0
- package/docs/design-system/README.md +22 -20
- package/docs/design-system/adoption-quality-remediation.md +87 -87
- package/docs/design-system/agent-usage.md +13 -13
- package/docs/design-system/appearance-presets.md +189 -189
- package/docs/design-system/appearances/default.md +94 -94
- package/docs/design-system/appearances/rounded.md +95 -95
- package/docs/design-system/appearances/sharp.md +95 -95
- package/docs/design-system/component-docs-pattern.md +81 -81
- package/docs/design-system/component-implementation-ownership-audit.md +245 -244
- package/docs/design-system/component-quality-audit-2026-08-20.md +225 -223
- package/docs/design-system/component-showcase-consistency-report.md +219 -219
- package/docs/design-system/component-token-consistency-audit.md +173 -173
- package/docs/design-system/components/README.md +90 -76
- package/docs/design-system/components/accordion.md +53 -53
- package/docs/design-system/components/activity-feed.md +94 -94
- package/docs/design-system/components/activity-heatmap.md +57 -57
- package/docs/design-system/components/agent-input.md +85 -0
- package/docs/design-system/components/alert-dialog.md +72 -72
- package/docs/design-system/components/alert.md +98 -98
- package/docs/design-system/components/approval-card.md +134 -0
- package/docs/design-system/components/aspect-ratio.md +45 -45
- package/docs/design-system/components/attribute.md +89 -89
- package/docs/design-system/components/autocomplete.md +75 -75
- package/docs/design-system/components/avatar.md +54 -54
- package/docs/design-system/components/badge.md +54 -54
- package/docs/design-system/components/banner.md +87 -87
- package/docs/design-system/components/breadcrumbs.md +177 -176
- package/docs/design-system/components/button-group.md +98 -98
- package/docs/design-system/components/button.md +83 -80
- package/docs/design-system/components/card.md +88 -88
- package/docs/design-system/components/carousel.md +46 -46
- package/docs/design-system/components/catalog-components.md +47 -47
- package/docs/design-system/components/chart.md +95 -24
- package/docs/design-system/components/checkbox.md +54 -54
- package/docs/design-system/components/collapsible.md +67 -53
- package/docs/design-system/components/command.md +62 -62
- package/docs/design-system/components/context-menu.md +46 -46
- package/docs/design-system/components/date-picker.md +81 -79
- package/docs/design-system/components/divider.md +102 -102
- package/docs/design-system/components/empty-state.md +56 -56
- package/docs/design-system/components/field.md +70 -70
- package/docs/design-system/components/file-upload.md +187 -187
- package/docs/design-system/components/hover-card.md +48 -48
- package/docs/design-system/components/icons.md +48 -48
- package/docs/design-system/components/inline-citations.md +93 -0
- package/docs/design-system/components/input-group.md +58 -58
- package/docs/design-system/components/input-otp.md +56 -56
- package/docs/design-system/components/input.md +117 -61
- package/docs/design-system/components/item.md +59 -57
- package/docs/design-system/components/kbd.md +54 -49
- package/docs/design-system/components/label.md +49 -49
- package/docs/design-system/components/menu.md +71 -61
- package/docs/design-system/components/menubar.md +47 -47
- package/docs/design-system/components/modal.md +105 -105
- package/docs/design-system/components/native-select.md +54 -54
- package/docs/design-system/components/navigation-menu.md +50 -50
- package/docs/design-system/components/onboarding-step-list-item.md +82 -82
- package/docs/design-system/components/page-header.md +93 -86
- package/docs/design-system/components/pagination.md +57 -57
- package/docs/design-system/components/popover.md +60 -60
- package/docs/design-system/components/progress-slider.md +50 -50
- package/docs/design-system/components/progress.md +76 -76
- package/docs/design-system/components/radio-card.md +51 -51
- package/docs/design-system/components/radio-group.md +57 -57
- package/docs/design-system/components/resizable.md +44 -44
- package/docs/design-system/components/rolling-count.md +61 -0
- package/docs/design-system/components/scroll-area.md +51 -51
- package/docs/design-system/components/segmented-control.md +54 -54
- package/docs/design-system/components/select.md +68 -62
- package/docs/design-system/components/sheet.md +67 -67
- package/docs/design-system/components/shimmer-text.md +67 -0
- package/docs/design-system/components/sidebar.md +127 -76
- package/docs/design-system/components/skeleton.md +75 -75
- package/docs/design-system/components/slideout.md +65 -65
- package/docs/design-system/components/slider.md +63 -63
- package/docs/design-system/components/social-button.md +50 -50
- package/docs/design-system/components/spinner.md +62 -62
- package/docs/design-system/components/steps.md +65 -65
- package/docs/design-system/components/streaming-text.md +82 -0
- package/docs/design-system/components/table.md +419 -414
- package/docs/design-system/components/tabs.md +59 -55
- package/docs/design-system/components/tag.md +80 -80
- package/docs/design-system/components/task-list.md +95 -0
- package/docs/design-system/components/textarea.md +50 -50
- package/docs/design-system/components/thinking-reasoning.md +72 -0
- package/docs/design-system/components/thinking-state.md +67 -0
- package/docs/design-system/components/timeline.md +83 -83
- package/docs/design-system/components/toast.md +58 -58
- package/docs/design-system/components/toggle.md +81 -81
- package/docs/design-system/components/toolbar.md +92 -87
- package/docs/design-system/components/tooltip.md +94 -92
- package/docs/design-system/components/typography.md +18 -18
- package/docs/design-system/density-and-elevation.md +65 -61
- package/docs/design-system/design-system-test-missing-items.md +368 -368
- package/docs/design-system/direction-and-localization.md +23 -23
- package/docs/design-system/form-recipes.md +73 -73
- package/docs/design-system/gap-promotion-policy.md +21 -21
- package/docs/design-system/icons.md +74 -69
- package/docs/design-system/installation.md +70 -68
- package/docs/design-system/launch-comparison-shadcn.md +98 -98
- package/docs/design-system/registry-and-cli.md +64 -64
- package/docs/design-system/release-policy.md +30 -30
- package/docs/design-system/roadmap.md +14 -14
- package/docs/design-system/support-matrix.md +23 -23
- package/docs/design-system/tabs.md +54 -53
- package/docs/design-system/template-gap-audit.md +32 -0
- package/docs/design-system/templates.md +59 -0
- package/docs/design-system/token-governance.md +72 -60
- package/package.json +98 -98
- package/registry/component-contract.json +40 -40
- package/registry/components/accordion.tsx +155 -155
- package/registry/components/agent-input-parts.tsx +552 -0
- package/registry/components/agent-input-state.ts +156 -0
- package/registry/components/agent-input.css +307 -0
- package/registry/components/agent-input.tsx +382 -0
- package/registry/components/alert-dialog.tsx +297 -297
- package/registry/components/alert.tsx +293 -293
- package/registry/components/approval-card.css +409 -0
- package/registry/components/approval-card.tsx +401 -0
- package/registry/components/approval-frame.tsx +108 -0
- package/registry/components/approval-questions.tsx +559 -0
- package/registry/components/aspect-ratio.tsx +30 -30
- package/registry/components/attribute.tsx +454 -448
- package/registry/components/autocomplete.tsx +598 -651
- package/registry/components/avatar.tsx +385 -381
- package/registry/components/badge.tsx +629 -629
- package/registry/components/button-group.tsx +565 -565
- package/registry/components/button.tsx +127 -123
- package/registry/components/card.tsx +638 -638
- package/registry/components/carousel.tsx +296 -296
- package/registry/components/chart-block-data.ts +177 -0
- package/registry/components/chart-block.css +171 -0
- package/registry/components/chart-block.tsx +260 -0
- package/registry/components/chart-interactions.ts +123 -0
- package/registry/components/chart-options.cartesian.ts +162 -0
- package/registry/components/chart-options.paint.ts +99 -0
- package/registry/components/chart-options.parts.ts +72 -0
- package/registry/components/chart-options.radial.ts +109 -0
- package/registry/components/chart-options.ts +44 -0
- package/registry/components/chart-options.types.ts +67 -0
- package/registry/components/chart.tsx +203 -203
- package/registry/components/checkbox.tsx +247 -247
- package/registry/components/collapsible.tsx +109 -69
- package/registry/components/command.tsx +208 -208
- package/registry/components/context-menu.tsx +236 -236
- package/registry/components/data-chart.tsx +40 -0
- package/registry/components/date-picker.tsx +1289 -1277
- package/registry/components/echart-theme.ts +246 -0
- package/registry/components/echart.css +49 -0
- package/registry/components/echart.tsx +178 -0
- package/registry/components/expanded/ActivityFeed.tsx +227 -227
- package/registry/components/expanded/ActivityHeatmap.tsx +64 -64
- package/registry/components/expanded/Banner.tsx +179 -179
- package/registry/components/expanded/Breadcrumbs.tsx +131 -131
- package/registry/components/expanded/CatalogComponentsShowcase.tsx +205 -205
- package/registry/components/expanded/CatalogDivider.tsx +49 -49
- package/registry/components/expanded/EmptyState.tsx +155 -155
- package/registry/components/expanded/FileUpload.tsx +543 -543
- package/registry/components/expanded/OnboardingStepListItem.tsx +60 -59
- package/registry/components/expanded/PageHeader.tsx +179 -166
- package/registry/components/expanded/Slideout.tsx +108 -108
- package/registry/components/expanded/Steps.tsx +402 -402
- package/registry/components/expanded/Table.tsx +1092 -1071
- package/registry/components/expanded/Timeline.tsx +203 -203
- package/registry/components/expanded/activityFeed.css +248 -248
- package/registry/components/expanded/activityHeatmap.css +66 -66
- package/registry/components/expanded/banner.css +260 -255
- package/registry/components/expanded/breadcrumbs.css +140 -140
- package/registry/components/expanded/catalogComponentsShowcase.css +87 -87
- package/registry/components/expanded/divider.css +75 -75
- package/registry/components/expanded/emptyState.css +111 -111
- package/registry/components/expanded/fileUpload.css +457 -457
- package/registry/components/expanded/onboardingStepListItem.css +135 -126
- package/registry/components/expanded/pageHeader.css +248 -290
- package/registry/components/expanded/slideout.css +276 -276
- package/registry/components/expanded/steps.css +356 -356
- package/registry/components/expanded/table.css +606 -603
- package/registry/components/expanded/timeline.css +286 -286
- package/registry/components/field.tsx +283 -283
- package/registry/components/hover-card.tsx +48 -48
- package/registry/components/inline-citations.css +126 -0
- package/registry/components/inline-citations.tsx +292 -0
- package/registry/components/input-content.ts +107 -107
- package/registry/components/input-group.tsx +130 -130
- package/registry/components/input-otp.tsx +584 -584
- package/registry/components/input.tsx +990 -972
- package/registry/components/item.tsx +189 -189
- package/registry/components/kbd.tsx +246 -151
- package/registry/components/label.tsx +78 -78
- package/registry/components/menu.tsx +978 -986
- package/registry/components/menubar.tsx +226 -226
- package/registry/components/modal.tsx +872 -872
- package/registry/components/native-select.tsx +205 -205
- package/registry/components/navigation-menu.tsx +171 -171
- package/registry/components/pagination.css +36 -36
- package/registry/components/pagination.tsx +560 -555
- package/registry/components/popover.tsx +338 -338
- package/registry/components/progress-slider.tsx +216 -216
- package/registry/components/radio-card.tsx +676 -677
- package/registry/components/radio-group.tsx +570 -570
- package/registry/components/resizable.tsx +108 -108
- package/registry/components/rolling-count.css +37 -0
- package/registry/components/rolling-count.tsx +110 -0
- package/registry/components/scroll-area.tsx +91 -91
- package/registry/components/segmented-control.tsx +87 -87
- package/registry/components/select-content.tsx +218 -218
- package/registry/components/select.tsx +937 -932
- package/registry/components/sheet.tsx +305 -305
- package/registry/components/shimmer-text.css +69 -0
- package/registry/components/shimmer-text.tsx +43 -0
- package/registry/components/sidebar.tsx +1433 -358
- package/registry/components/skeleton.css +54 -54
- package/registry/components/skeleton.tsx +482 -482
- package/registry/components/slider.tsx +380 -380
- package/registry/components/social-button.tsx +387 -387
- package/registry/components/spinner.tsx +78 -78
- package/registry/components/streaming-text.css +45 -0
- package/registry/components/streaming-text.tsx +165 -0
- package/registry/components/table-elements.tsx +128 -128
- package/registry/components/tabs.css +222 -218
- package/registry/components/tabs.tsx +241 -241
- package/registry/components/tag.tsx +423 -423
- package/registry/components/task-list.css +328 -0
- package/registry/components/task-list.tsx +429 -0
- package/registry/components/textarea.tsx +610 -610
- package/registry/components/thinking-reasoning.css +178 -0
- package/registry/components/thinking-reasoning.tsx +253 -0
- package/registry/components/thinking-state.css +8 -0
- package/registry/components/thinking-state.tsx +46 -0
- package/registry/components/toast.tsx +136 -136
- package/registry/components/toggle.tsx +256 -256
- package/registry/components/toolbar.tsx +539 -539
- package/registry/components/tooltip.tsx +433 -431
- package/registry/examples/agent-input-demo.tsx +90 -0
- package/registry/examples/alert-demo.tsx +34 -34
- package/registry/examples/alert-dialog-demo.tsx +42 -42
- package/registry/examples/approval-card-demo.tsx +83 -0
- package/registry/examples/aspect-ratio-demo.tsx +11 -11
- package/registry/examples/attribute-demo.tsx +65 -65
- package/registry/examples/autocomplete-demo.tsx +109 -109
- package/registry/examples/avatar-demo.tsx +132 -132
- package/registry/examples/badge-demo.tsx +69 -69
- package/registry/examples/button-demo.tsx +86 -83
- package/registry/examples/button-group-demo.tsx +63 -63
- package/registry/examples/card-demo.tsx +86 -86
- package/registry/examples/carousel-demo.tsx +43 -43
- package/registry/examples/chart-block-demo.tsx +5 -0
- package/registry/examples/chart-demo.tsx +18 -33
- package/registry/examples/checkbox-demo.tsx +62 -62
- package/registry/examples/collapsible-demo.tsx +16 -16
- package/registry/examples/collection-filter-bar-demo.tsx +135 -135
- package/registry/examples/command-demo.tsx +42 -42
- package/registry/examples/command-palette-demo.tsx +235 -236
- package/registry/examples/context-menu-demo.tsx +29 -29
- package/registry/examples/control-density-contract-demo.tsx +65 -61
- package/registry/examples/date-picker-demo.tsx +127 -127
- package/registry/examples/divider-demo.tsx +17 -17
- package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -29
- package/registry/examples/expanded/banner-demo.tsx +48 -48
- package/registry/examples/expanded/breadcrumbs-demo.tsx +59 -59
- package/registry/examples/expanded/empty-state-demo.tsx +39 -39
- package/registry/examples/expanded/file-upload-demo.tsx +60 -60
- package/registry/examples/expanded/onboarding-step-demo.tsx +11 -11
- package/registry/examples/expanded/slideout-demo.tsx +15 -15
- package/registry/examples/expanded/steps-demo.tsx +29 -29
- package/registry/examples/expanded/tabs-demo.tsx +13 -13
- package/registry/examples/expanded/timeline-demo.tsx +18 -18
- package/registry/examples/field-demo.tsx +51 -51
- package/registry/examples/hover-card-demo.tsx +23 -23
- package/registry/examples/inline-citations-demo.tsx +31 -0
- package/registry/examples/input-actions-demo.tsx +36 -0
- package/registry/examples/input-demo.tsx +87 -87
- package/registry/examples/input-group-demo.tsx +16 -16
- package/registry/examples/input-otp-demo.tsx +72 -72
- package/registry/examples/item-demo.tsx +46 -46
- package/registry/examples/kbd-demo.tsx +12 -11
- package/registry/examples/label-demo.tsx +20 -20
- package/registry/examples/menu-demo.tsx +122 -122
- package/registry/examples/menubar-demo.tsx +34 -34
- package/registry/examples/modal-demo.tsx +74 -74
- package/registry/examples/native-select-demo.tsx +16 -16
- package/registry/examples/navigation-menu-demo.tsx +29 -29
- package/registry/examples/pagination-demo.tsx +20 -20
- package/registry/examples/popover-demo.tsx +547 -546
- package/registry/examples/progress-demo.tsx +37 -37
- package/registry/examples/progress-slider-demo.tsx +29 -29
- package/registry/examples/radio-card-demo.tsx +51 -51
- package/registry/examples/radio-group-demo.tsx +62 -62
- package/registry/examples/resizable-demo.tsx +22 -22
- package/registry/examples/results-toolbar-demo.tsx +44 -44
- package/registry/examples/rolling-count-demo.tsx +39 -0
- package/registry/examples/scroll-area-demo.tsx +15 -15
- package/registry/examples/segmented-control-demo.tsx +39 -39
- package/registry/examples/select-demo.tsx +87 -87
- package/registry/examples/sheet-demo.tsx +47 -47
- package/registry/examples/shimmer-text-demo.tsx +20 -0
- package/registry/examples/sidebar-demo.tsx +101 -57
- package/registry/examples/slider-demo.tsx +31 -31
- package/registry/examples/social-button-demo.tsx +61 -61
- package/registry/examples/spinner-demo.tsx +59 -59
- package/registry/examples/streaming-text-demo.tsx +28 -0
- package/registry/examples/tabs-demo.tsx +13 -13
- package/registry/examples/tag-demo.tsx +29 -29
- package/registry/examples/task-list-demo.tsx +74 -0
- package/registry/examples/textarea-demo.tsx +79 -79
- package/registry/examples/thinking-reasoning-demo.tsx +74 -0
- package/registry/examples/thinking-state-demo.tsx +13 -0
- package/registry/examples/toast-demo.tsx +35 -35
- package/registry/examples/toggle-demo.tsx +59 -59
- package/registry/examples/tooltip-demo.tsx +115 -115
- package/registry/guidance/USAGE.md +27 -27
- package/registry/guidance/charts.LICENSE.txt +24 -0
- package/registry/hooks/use-controllable-state.ts +33 -0
- package/registry/hooks/use-direction.ts +207 -207
- package/registry/hooks/use-listbox-navigation.ts +73 -0
- package/registry/hooks/use-motion-end.ts +55 -0
- package/registry/hooks/use-reduced-motion.ts +28 -0
- package/registry/index.json +1634 -184
- package/registry/styles/globals.css +1462 -1570
- package/registry.json +364 -10
- package/schema/config.schema.json +51 -51
- package/schema/registry.schema.json +194 -190
- package/schema/tokens.schema.json +167 -163
- package/src/cli/command-line.js +194 -194
- package/src/cli/config-editors.js +9 -9
- package/src/cli/doctor.js +399 -399
- package/src/cli/file-transaction.js +302 -295
- package/src/cli/global-css.js +153 -153
- package/src/cli/index.js +1002 -1009
- package/src/cli/install-plan.js +592 -592
- package/src/cli/install-receipt.js +171 -171
- package/src/cli/jsonc.js +203 -203
- package/src/cli/package-install-state.js +254 -254
- package/src/cli/package-manager.js +238 -238
- package/src/cli/package-plan.js +185 -185
- package/src/cli/package-version.js +97 -97
- package/src/cli/registry-query.js +207 -207
- package/src/cli/reporting.js +55 -55
- package/src/cli/schema-validation.js +19 -19
- package/src/cli/source-scanner.js +686 -686
- package/src/cli/vite-config.js +478 -478
- package/tokens/banhaten.tokens.json +458 -224
package/src/cli/package-plan.js
CHANGED
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
import {
|
|
2
|
-
findPackageDependencies,
|
|
3
|
-
reconcileDependencyRange,
|
|
4
|
-
} from "./package-version.js"
|
|
5
|
-
|
|
6
|
-
const DEPENDENCY_SECTIONS = [
|
|
7
|
-
"dependencies",
|
|
8
|
-
"devDependencies",
|
|
9
|
-
"peerDependencies",
|
|
10
|
-
"optionalDependencies",
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
export function createPackageDependencyPlan(packageJson, changes) {
|
|
14
|
-
if (!packageJson || typeof packageJson !== "object" || Array.isArray(packageJson)) {
|
|
15
|
-
throw new Error("package.json root must be an object.")
|
|
16
|
-
}
|
|
17
|
-
validatePackageDependencySections(packageJson)
|
|
18
|
-
const requirements = collectPackageRequirements(changes)
|
|
19
|
-
const operations = []
|
|
20
|
-
|
|
21
|
-
for (const requirement of requirements.values()) {
|
|
22
|
-
const declarations = findPackageDependencies(packageJson, requirement.name)
|
|
23
|
-
|
|
24
|
-
if (declarations.length === 0) {
|
|
25
|
-
operations.push({
|
|
26
|
-
kind: "add",
|
|
27
|
-
name: requirement.name,
|
|
28
|
-
range: requirement.range,
|
|
29
|
-
section: requirement.section,
|
|
30
|
-
})
|
|
31
|
-
continue
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
for (const declaration of declarations) {
|
|
35
|
-
const resolution = reconcileDependencyRange(
|
|
36
|
-
declaration.version,
|
|
37
|
-
requirement.range
|
|
38
|
-
)
|
|
39
|
-
assertDependencyResolution(
|
|
40
|
-
requirement.name,
|
|
41
|
-
declaration,
|
|
42
|
-
requirement.range,
|
|
43
|
-
resolution
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
if (resolution.status === "strengthened") {
|
|
47
|
-
operations.push({
|
|
48
|
-
kind: "strengthen",
|
|
49
|
-
name: requirement.name,
|
|
50
|
-
range: resolution.range,
|
|
51
|
-
section: declaration.section,
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
operations,
|
|
59
|
-
requirements: [...requirements.values()],
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function applyPackageDependencyPlan(packageJson, operations) {
|
|
64
|
-
const touchedSections = new Set()
|
|
65
|
-
|
|
66
|
-
for (const operation of operations) {
|
|
67
|
-
const dependencies = packageJson[operation.section] || {}
|
|
68
|
-
dependencies[operation.name] = operation.range
|
|
69
|
-
packageJson[operation.section] = dependencies
|
|
70
|
-
touchedSections.add(operation.section)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
for (const section of touchedSections) {
|
|
74
|
-
packageJson[section] = sortObject(packageJson[section])
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function mergeDependencyRequirements(target, incoming, source) {
|
|
79
|
-
for (const [name, range] of Object.entries(incoming)) {
|
|
80
|
-
if (!Object.hasOwn(target, name)) {
|
|
81
|
-
target[name] = range
|
|
82
|
-
continue
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const resolution = reconcileDependencyRange(target[name], range)
|
|
86
|
-
if (resolution.status === "satisfied") continue
|
|
87
|
-
if (resolution.status === "strengthened") {
|
|
88
|
-
target[name] = resolution.range
|
|
89
|
-
continue
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
throw new Error(
|
|
93
|
-
`${source} declares dependency "${name}" as "${range}", which cannot be combined safely with "${target[name]}".`
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function collectPackageRequirements(changes) {
|
|
99
|
-
const requirements = new Map()
|
|
100
|
-
|
|
101
|
-
for (const section of ["dependencies", "devDependencies"]) {
|
|
102
|
-
for (const [name, range] of Object.entries(changes[section] || {})) {
|
|
103
|
-
const validation = reconcileDependencyRange(range, range)
|
|
104
|
-
if (validation.status === "invalid-required") {
|
|
105
|
-
throw new Error(
|
|
106
|
-
`Banhaten declares an invalid semantic version range for "${name}": "${range}".`
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const current = requirements.get(name)
|
|
111
|
-
if (!current) {
|
|
112
|
-
requirements.set(name, { name, range, section })
|
|
113
|
-
continue
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (section === "dependencies") current.section = section
|
|
117
|
-
|
|
118
|
-
const resolution = reconcileDependencyRange(current.range, range)
|
|
119
|
-
if (resolution.status === "satisfied") continue
|
|
120
|
-
if (resolution.status === "strengthened") {
|
|
121
|
-
current.range = resolution.range
|
|
122
|
-
continue
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
throw new Error(
|
|
126
|
-
`Banhaten registry dependency conflict for "${name}": ` +
|
|
127
|
-
`"${current.range}" and "${range}" cannot be combined safely.`
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return requirements
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function validatePackageDependencySections(packageJson) {
|
|
136
|
-
for (const section of DEPENDENCY_SECTIONS) {
|
|
137
|
-
const dependencies = packageJson[section]
|
|
138
|
-
if (
|
|
139
|
-
dependencies !== undefined &&
|
|
140
|
-
(!dependencies ||
|
|
141
|
-
typeof dependencies !== "object" ||
|
|
142
|
-
Array.isArray(dependencies))
|
|
143
|
-
) {
|
|
144
|
-
throw new Error(`package.json ${section} must be an object.`)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function assertDependencyResolution(name, declaration, requiredRange, resolution) {
|
|
150
|
-
if (resolution.status === "satisfied" || resolution.status === "strengthened") {
|
|
151
|
-
return
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (resolution.status === "unsupported") {
|
|
155
|
-
throw new Error(
|
|
156
|
-
`dependency version conflict for "${name}": ${declaration.section} declares unsupported non-semver spec ` +
|
|
157
|
-
`"${declaration.version}", but Banhaten requires "${requiredRange}".`
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (resolution.status === "partial-overlap") {
|
|
162
|
-
throw new Error(
|
|
163
|
-
`dependency range conflict for "${name}": ${declaration.section} declares "${declaration.version}", ` +
|
|
164
|
-
`which only partially overlaps Banhaten's required "${requiredRange}". ` +
|
|
165
|
-
"Declare a range contained by both requirements."
|
|
166
|
-
)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (resolution.status === "invalid-required") {
|
|
170
|
-
throw new Error(
|
|
171
|
-
`Banhaten declares an invalid semantic version range for "${name}": "${requiredRange}".`
|
|
172
|
-
)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
throw new Error(
|
|
176
|
-
`dependency version conflict for "${name}": ${declaration.section} declares "${declaration.version}", ` +
|
|
177
|
-
`but Banhaten requires "${requiredRange}".`
|
|
178
|
-
)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function sortObject(value) {
|
|
182
|
-
return Object.fromEntries(
|
|
183
|
-
Object.entries(value).sort(([left], [right]) => left.localeCompare(right))
|
|
184
|
-
)
|
|
185
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
findPackageDependencies,
|
|
3
|
+
reconcileDependencyRange,
|
|
4
|
+
} from "./package-version.js"
|
|
5
|
+
|
|
6
|
+
const DEPENDENCY_SECTIONS = [
|
|
7
|
+
"dependencies",
|
|
8
|
+
"devDependencies",
|
|
9
|
+
"peerDependencies",
|
|
10
|
+
"optionalDependencies",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
export function createPackageDependencyPlan(packageJson, changes) {
|
|
14
|
+
if (!packageJson || typeof packageJson !== "object" || Array.isArray(packageJson)) {
|
|
15
|
+
throw new Error("package.json root must be an object.")
|
|
16
|
+
}
|
|
17
|
+
validatePackageDependencySections(packageJson)
|
|
18
|
+
const requirements = collectPackageRequirements(changes)
|
|
19
|
+
const operations = []
|
|
20
|
+
|
|
21
|
+
for (const requirement of requirements.values()) {
|
|
22
|
+
const declarations = findPackageDependencies(packageJson, requirement.name)
|
|
23
|
+
|
|
24
|
+
if (declarations.length === 0) {
|
|
25
|
+
operations.push({
|
|
26
|
+
kind: "add",
|
|
27
|
+
name: requirement.name,
|
|
28
|
+
range: requirement.range,
|
|
29
|
+
section: requirement.section,
|
|
30
|
+
})
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const declaration of declarations) {
|
|
35
|
+
const resolution = reconcileDependencyRange(
|
|
36
|
+
declaration.version,
|
|
37
|
+
requirement.range
|
|
38
|
+
)
|
|
39
|
+
assertDependencyResolution(
|
|
40
|
+
requirement.name,
|
|
41
|
+
declaration,
|
|
42
|
+
requirement.range,
|
|
43
|
+
resolution
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if (resolution.status === "strengthened") {
|
|
47
|
+
operations.push({
|
|
48
|
+
kind: "strengthen",
|
|
49
|
+
name: requirement.name,
|
|
50
|
+
range: resolution.range,
|
|
51
|
+
section: declaration.section,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
operations,
|
|
59
|
+
requirements: [...requirements.values()],
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function applyPackageDependencyPlan(packageJson, operations) {
|
|
64
|
+
const touchedSections = new Set()
|
|
65
|
+
|
|
66
|
+
for (const operation of operations) {
|
|
67
|
+
const dependencies = packageJson[operation.section] || {}
|
|
68
|
+
dependencies[operation.name] = operation.range
|
|
69
|
+
packageJson[operation.section] = dependencies
|
|
70
|
+
touchedSections.add(operation.section)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const section of touchedSections) {
|
|
74
|
+
packageJson[section] = sortObject(packageJson[section])
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function mergeDependencyRequirements(target, incoming, source) {
|
|
79
|
+
for (const [name, range] of Object.entries(incoming)) {
|
|
80
|
+
if (!Object.hasOwn(target, name)) {
|
|
81
|
+
target[name] = range
|
|
82
|
+
continue
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const resolution = reconcileDependencyRange(target[name], range)
|
|
86
|
+
if (resolution.status === "satisfied") continue
|
|
87
|
+
if (resolution.status === "strengthened") {
|
|
88
|
+
target[name] = resolution.range
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
throw new Error(
|
|
93
|
+
`${source} declares dependency "${name}" as "${range}", which cannot be combined safely with "${target[name]}".`
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function collectPackageRequirements(changes) {
|
|
99
|
+
const requirements = new Map()
|
|
100
|
+
|
|
101
|
+
for (const section of ["dependencies", "devDependencies"]) {
|
|
102
|
+
for (const [name, range] of Object.entries(changes[section] || {})) {
|
|
103
|
+
const validation = reconcileDependencyRange(range, range)
|
|
104
|
+
if (validation.status === "invalid-required") {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Banhaten declares an invalid semantic version range for "${name}": "${range}".`
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const current = requirements.get(name)
|
|
111
|
+
if (!current) {
|
|
112
|
+
requirements.set(name, { name, range, section })
|
|
113
|
+
continue
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (section === "dependencies") current.section = section
|
|
117
|
+
|
|
118
|
+
const resolution = reconcileDependencyRange(current.range, range)
|
|
119
|
+
if (resolution.status === "satisfied") continue
|
|
120
|
+
if (resolution.status === "strengthened") {
|
|
121
|
+
current.range = resolution.range
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
throw new Error(
|
|
126
|
+
`Banhaten registry dependency conflict for "${name}": ` +
|
|
127
|
+
`"${current.range}" and "${range}" cannot be combined safely.`
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return requirements
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function validatePackageDependencySections(packageJson) {
|
|
136
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
137
|
+
const dependencies = packageJson[section]
|
|
138
|
+
if (
|
|
139
|
+
dependencies !== undefined &&
|
|
140
|
+
(!dependencies ||
|
|
141
|
+
typeof dependencies !== "object" ||
|
|
142
|
+
Array.isArray(dependencies))
|
|
143
|
+
) {
|
|
144
|
+
throw new Error(`package.json ${section} must be an object.`)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function assertDependencyResolution(name, declaration, requiredRange, resolution) {
|
|
150
|
+
if (resolution.status === "satisfied" || resolution.status === "strengthened") {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (resolution.status === "unsupported") {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`dependency version conflict for "${name}": ${declaration.section} declares unsupported non-semver spec ` +
|
|
157
|
+
`"${declaration.version}", but Banhaten requires "${requiredRange}".`
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (resolution.status === "partial-overlap") {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`dependency range conflict for "${name}": ${declaration.section} declares "${declaration.version}", ` +
|
|
164
|
+
`which only partially overlaps Banhaten's required "${requiredRange}". ` +
|
|
165
|
+
"Declare a range contained by both requirements."
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (resolution.status === "invalid-required") {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Banhaten declares an invalid semantic version range for "${name}": "${requiredRange}".`
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
throw new Error(
|
|
176
|
+
`dependency version conflict for "${name}": ${declaration.section} declares "${declaration.version}", ` +
|
|
177
|
+
`but Banhaten requires "${requiredRange}".`
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function sortObject(value) {
|
|
182
|
+
return Object.fromEntries(
|
|
183
|
+
Object.entries(value).sort(([left], [right]) => left.localeCompare(right))
|
|
184
|
+
)
|
|
185
|
+
}
|
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
import semver from "semver"
|
|
2
|
-
|
|
3
|
-
const DEPENDENCY_SECTIONS = [
|
|
4
|
-
"dependencies",
|
|
5
|
-
"devDependencies",
|
|
6
|
-
"peerDependencies",
|
|
7
|
-
"optionalDependencies",
|
|
8
|
-
]
|
|
9
|
-
|
|
10
|
-
export function findPackageDependencies(packageJson, name) {
|
|
11
|
-
const declarations = []
|
|
12
|
-
|
|
13
|
-
for (const section of DEPENDENCY_SECTIONS) {
|
|
14
|
-
const dependencies = packageJson[section]
|
|
15
|
-
if (
|
|
16
|
-
dependencies &&
|
|
17
|
-
typeof dependencies === "object" &&
|
|
18
|
-
!Array.isArray(dependencies) &&
|
|
19
|
-
Object.hasOwn(dependencies, name)
|
|
20
|
-
) {
|
|
21
|
-
declarations.push({
|
|
22
|
-
section,
|
|
23
|
-
version: dependencies[name],
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return declarations
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function reconcileDependencyRange(declaredRange, requiredRange) {
|
|
32
|
-
const required = parseRange(requiredRange)
|
|
33
|
-
if (required.status !== "valid") {
|
|
34
|
-
return {
|
|
35
|
-
status: "invalid-required",
|
|
36
|
-
range: requiredRange,
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const declared = parseRange(declaredRange)
|
|
41
|
-
if (declared.status === "invalid") {
|
|
42
|
-
return {
|
|
43
|
-
status: "unsupported",
|
|
44
|
-
range: declaredRange,
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (declared.status === "empty") {
|
|
48
|
-
return {
|
|
49
|
-
status: "conflict",
|
|
50
|
-
range: declaredRange,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (semver.subset(declared.range, required.range)) {
|
|
55
|
-
return {
|
|
56
|
-
status: "satisfied",
|
|
57
|
-
range: declaredRange,
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (semver.subset(required.range, declared.range)) {
|
|
62
|
-
return {
|
|
63
|
-
status: "strengthened",
|
|
64
|
-
range: requiredRange.trim(),
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (semver.intersects(declared.range, required.range)) {
|
|
69
|
-
return {
|
|
70
|
-
status: "partial-overlap",
|
|
71
|
-
range: declaredRange,
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
status: "conflict",
|
|
77
|
-
range: declaredRange,
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function dependencyVersionSatisfies(version, requiredRange) {
|
|
82
|
-
if (typeof version !== "string" || semver.valid(version) === null) return false
|
|
83
|
-
const required = parseRange(requiredRange)
|
|
84
|
-
if (required.status !== "valid") return false
|
|
85
|
-
return semver.satisfies(version, required.range)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function parseRange(value) {
|
|
89
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
90
|
-
return { status: "invalid" }
|
|
91
|
-
}
|
|
92
|
-
if (semver.validRange(value) === null) return { status: "invalid" }
|
|
93
|
-
|
|
94
|
-
const range = new semver.Range(value)
|
|
95
|
-
if (semver.minVersion(range) === null) return { status: "empty" }
|
|
96
|
-
return { range, status: "valid" }
|
|
97
|
-
}
|
|
1
|
+
import semver from "semver"
|
|
2
|
+
|
|
3
|
+
const DEPENDENCY_SECTIONS = [
|
|
4
|
+
"dependencies",
|
|
5
|
+
"devDependencies",
|
|
6
|
+
"peerDependencies",
|
|
7
|
+
"optionalDependencies",
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
export function findPackageDependencies(packageJson, name) {
|
|
11
|
+
const declarations = []
|
|
12
|
+
|
|
13
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
14
|
+
const dependencies = packageJson[section]
|
|
15
|
+
if (
|
|
16
|
+
dependencies &&
|
|
17
|
+
typeof dependencies === "object" &&
|
|
18
|
+
!Array.isArray(dependencies) &&
|
|
19
|
+
Object.hasOwn(dependencies, name)
|
|
20
|
+
) {
|
|
21
|
+
declarations.push({
|
|
22
|
+
section,
|
|
23
|
+
version: dependencies[name],
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return declarations
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function reconcileDependencyRange(declaredRange, requiredRange) {
|
|
32
|
+
const required = parseRange(requiredRange)
|
|
33
|
+
if (required.status !== "valid") {
|
|
34
|
+
return {
|
|
35
|
+
status: "invalid-required",
|
|
36
|
+
range: requiredRange,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const declared = parseRange(declaredRange)
|
|
41
|
+
if (declared.status === "invalid") {
|
|
42
|
+
return {
|
|
43
|
+
status: "unsupported",
|
|
44
|
+
range: declaredRange,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (declared.status === "empty") {
|
|
48
|
+
return {
|
|
49
|
+
status: "conflict",
|
|
50
|
+
range: declaredRange,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (semver.subset(declared.range, required.range)) {
|
|
55
|
+
return {
|
|
56
|
+
status: "satisfied",
|
|
57
|
+
range: declaredRange,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (semver.subset(required.range, declared.range)) {
|
|
62
|
+
return {
|
|
63
|
+
status: "strengthened",
|
|
64
|
+
range: requiredRange.trim(),
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (semver.intersects(declared.range, required.range)) {
|
|
69
|
+
return {
|
|
70
|
+
status: "partial-overlap",
|
|
71
|
+
range: declaredRange,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
status: "conflict",
|
|
77
|
+
range: declaredRange,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function dependencyVersionSatisfies(version, requiredRange) {
|
|
82
|
+
if (typeof version !== "string" || semver.valid(version) === null) return false
|
|
83
|
+
const required = parseRange(requiredRange)
|
|
84
|
+
if (required.status !== "valid") return false
|
|
85
|
+
return semver.satisfies(version, required.range)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function parseRange(value) {
|
|
89
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
90
|
+
return { status: "invalid" }
|
|
91
|
+
}
|
|
92
|
+
if (semver.validRange(value) === null) return { status: "invalid" }
|
|
93
|
+
|
|
94
|
+
const range = new semver.Range(value)
|
|
95
|
+
if (semver.minVersion(range) === null) return { status: "empty" }
|
|
96
|
+
return { range, status: "valid" }
|
|
97
|
+
}
|