Skip to content

Commit b65b2b6

Browse files
committed
Update docs
1 parent eeb12b9 commit b65b2b6

File tree

1 file changed

+79
-23
lines changed

1 file changed

+79
-23
lines changed

docs/PACKAGE_DEPENDENCIES.md

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@ This document describes the allowed dependency structure within the CDC Open Viz
66

77
The CDC Open Viz monorepo follows a specific dependency architecture to maintain clean separation of concerns and prevent circular dependencies. The standalone build tests enforce these rules to ensure packages can be built independently.
88

9+
## TL;DR
10+
11+
**Quick Reference:**
12+
13+
- **Core** (`@cdc/core`) → Depends on nothing (foundation)
14+
- **Visualizations** (`chart`, `map`, `data-table`, etc.) → Depend only on Core
15+
- **Orchestrators** (`dashboard`, `editor`) → Can depend on everything
16+
917
## Dependency Rules
1018

1119
### ✅ Allowed Dependencies
1220

1321
1. **Core Package (`@cdc/core`)**
1422

15-
- **Can depend on ANY other package**
23+
- **Cannot depend on any other internal packages** (foundation layer)
1624
- **Any package can depend on `@cdc/core`**
1725
- Core contains shared utilities, types, components, and helpers used across the monorepo
1826
- Examples: `import { cloneConfig } from '@cdc/core/helpers/cloneConfig'`
@@ -58,16 +66,33 @@ Individual visualization packages should be self-contained:
5866
## Current Package Structure
5967

6068
```
61-
@cdc/core ← Base package (can be imported by all)
62-
├── @cdc/chart ← Standalone visualization
63-
├── @cdc/map ← Standalone visualization
64-
├── @cdc/data-table ← Standalone visualization
65-
├── @cdc/data-bite ← Standalone visualization
66-
├── @cdc/waffle-chart ← Standalone visualization
67-
├── @cdc/filtered-text ← Standalone visualization
68-
├── @cdc/markup-include← Standalone visualization
69-
├── @cdc/dashboard ← Orchestrator (can import from all)
70-
└── @cdc/editor ← Configuration tool (can import from all)
69+
┌─────────────────────────────────────────────────────────┐
70+
│ Tier 3: Orchestrators (can import from all packages) │
71+
├─────────────────────────────────────────────────────────┤
72+
@cdc/dashboard ← Combines multiple visualizations │
73+
@cdc/editor ← Configuration tool for all packages │
74+
└─────────────────────────────────────────────────────────┘
75+
│ │
76+
↓ (depends on) │
77+
┌─────────────────────────────────────────┐ │
78+
│ Tier 2: Standalone Visualizations │ │
79+
│ (depend only on core) │ │
80+
├─────────────────────────────────────────┤ │
81+
@cdc/chart │ │
82+
@cdc/map │ │
83+
@cdc/data-table │ │
84+
@cdc/data-bite │ │
85+
@cdc/waffle-chart │ │
86+
@cdc/filtered-text │ │
87+
@cdc/markup-include │ │
88+
└─────────────────────────────────────────┘ │
89+
│ │
90+
↓ (depends on) ↓ (also depends on)
91+
┌─────────────────────────────────────────────────────────┐
92+
│ Tier 1: Foundation (no internal package dependencies) │
93+
├─────────────────────────────────────────────────────────┤
94+
@cdc/core ← Shared utilities, types, components │
95+
└─────────────────────────────────────────────────────────┘
7196
```
7297
7398
## Rationale
@@ -81,9 +106,9 @@ Individual visualization packages should be self-contained:
81106
82107
### Special Cases
83108
84-
- **Dashboard**: Acts as a composition root, combining multiple visualizations
85-
- **Editor**: Needs access to all components for configuration UI and live previews
86-
- **Core**: Provides shared infrastructure (utilities, types, base components)
109+
- **Core**: Foundation layer providing shared infrastructure (utilities, types, base components). Cannot depend on other packages to prevent circular dependencies.
110+
- **Dashboard**: Acts as a composition root, combining multiple visualizations. Can import from all packages.
111+
- **Editor**: Needs access to all components for configuration UI and live previews. Can import from all packages.
87112
88113
## Exemptions
89114
@@ -102,6 +127,32 @@ The dependency rules are enforced by:
102127
103128
1. **Standalone Build Tests**: Each package has a test that verifies it can be built in isolation
104129
2. **Code Reviews**: Manual verification during pull request reviews
130+
3. **Monitoring Commands**: Grep-based commands to detect cross-package imports (see Monitoring section)
131+
132+
## Known Limitations
133+
134+
### TypeScript Type-Only Imports
135+
136+
TypeScript type-only imports (using the `type` keyword) can slip through standalone build tests:
137+
138+
```typescript
139+
// This violates architecture but may not fail builds
140+
import { type DashboardConfig } from '@cdc/dashboard/src/types/DashboardConfig'
141+
```
142+
143+
**Why builds still succeed:**
144+
145+
- Type-only imports are stripped during compilation and create no runtime dependency
146+
- TypeScript may not fail when the imported package isn't installed
147+
- The package can build successfully in isolation
148+
149+
**Important:** These are still **architectural violations** even if they don't break builds. Type-only imports:
150+
151+
- Create conceptual coupling between packages
152+
- Can evolve into runtime imports over time
153+
- Violate the intended dependency hierarchy
154+
155+
**Solution:** Move shared types to `@cdc/core` so both packages can reference them without violating the architecture.
105156

106157
## Resolving Violations
107158

@@ -153,15 +204,21 @@ interface ComponentProps {
153204
import { cloneConfig } from '@cdc/core/helpers/cloneConfig'
154205
import { DataTableConfig } from '@cdc/core/types/DataTable'
155206

156-
// Dashboard can import from anywhere
207+
// Dashboard can import from anywhere (visualizations + core)
157208
import CdcChart from '@cdc/chart/src/CdcChartComponent'
158-
159-
// Editor can import from anywhere
160209
import CdcMap from '@cdc/map/src/CdcMapComponent'
210+
import { useReduceData } from '@cdc/core/helpers/useReduceData'
211+
212+
// Editor can import from anywhere (visualizations + core + dashboard)
213+
import CdcChart from '@cdc/chart/src/CdcChart'
214+
import { stripConfig } from '@cdc/dashboard/src/helpers/formatConfigBeforeSave'
215+
import { cloneConfig } from '@cdc/core/helpers/cloneConfig'
161216
```
162217

163218
### ❌ Invalid Imports
164219

220+
**Example: In the `@cdc/map` package** (or any Tier 2/1 visualization package)
221+
165222
```typescript
166223
// Explicit package imports (PROHIBITED)
167224
import { DashboardConfig } from '@cdc/dashboard/src/types/DashboardConfig'
@@ -186,11 +243,10 @@ To check for dependency violations:
186243
# Run standalone build tests
187244
npx lerna run test
188245

189-
# Search for explicit cross-package imports (excluding stories)
190-
grep -r "from '@cdc/[^c]" packages/*/src --exclude-dir=dashboard --exclude-dir=editor --exclude="*.stories.*" | grep -v "/_stories/"
246+
# Search for explicit cross-package imports (excluding core, stories, dashboard, and editor)
247+
grep -r "from '@cdc/" packages/*/src --exclude="*.stories.*" | grep -v "/_stories/" | grep -v "@cdc/core" | grep -v "packages/dashboard/" | grep -v "packages/editor/"
191248
192-
# Search for relative imports that might cross package boundaries (excluding stories)
193-
# Look for imports with multiple ../ that could reach sibling packages
194-
grep -r "from '\.\./\.\./\.\." packages/*/src --exclude-dir=dashboard --exclude-dir=editor --exclude="*.stories.*" | grep -v "/_stories/"
195-
grep -r "from \"\.\./\.\./\.\." packages/*/src --exclude-dir=dashboard --exclude-dir=editor --exclude="*.stories.*" | grep -v "/_stories/"
249+
# Search for relative imports that explicitly reference other package names
250+
# These patterns catch imports like: from '../../chart/...' or from '../../../map/src/...'
251+
grep -rE "from ['\"]\.\..*/(chart|map|data-table|data-bite|waffle-chart|filtered-text|markup-include|dashboard|editor)/" packages/*/src --exclude="*.stories.*" | grep -v "/_stories/" | grep -v "packages/dashboard/" | grep -v "packages/editor/"
196252
```

0 commit comments

Comments
 (0)