
Security News
Lovable’s OJ Rewrites Vite’s Dev Server in Rust as AI Lowers the Cost of Forking Open Source
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.
@bfra.me/workspace-analyzer
Advanced tools
Comprehensive monorepo static analysis for workspace configuration, dependencies, and architecture
Comprehensive monorepo static analysis for workspace configuration, dependencies, and architecture.
package.json, tsconfig.json, eslint.config.ts, and tsup.config.ts files@clack/prompts with progress reportingpnpm add -D @bfra.me/workspace-analyzer
# Analyze current workspace
npx workspace-analyzer
# Interactive mode with package selection
npx workspace-analyzer --interactive
# CI-friendly JSON output
npx workspace-analyzer --json > analysis-report.json
The CLI provides a modern, interactive experience powered by @clack/prompts:
# Basic analysis
workspace-analyzer [path]
# With configuration file
workspace-analyzer --config workspace-analyzer.config.ts
# Output formats
workspace-analyzer --json # JSON output
workspace-analyzer --markdown # Markdown report
# Filtering options
workspace-analyzer --min-severity warning
workspace-analyzer --categories dependency,architecture
# Analysis control
workspace-analyzer --no-cache # Disable caching
workspace-analyzer --verbose # Detailed output
workspace-analyzer --dry-run # Preview without analysis
| Option | Description |
|---|---|
--config <path> | Path to configuration file |
--json | Output results as JSON |
--markdown | Output results as Markdown |
--min-severity <level> | Minimum severity to report (info, warning, error, critical) |
--categories <list> | Comma-separated categories to analyze |
--include <patterns> | Glob patterns for files to include |
--exclude <patterns> | Glob patterns for files to exclude |
--no-cache | Disable incremental analysis caching |
--cache-dir <path> | Custom cache directory |
--concurrency <n> | Maximum parallel operations |
--verbose | Enable verbose logging |
--quiet | Suppress non-essential output |
--dry-run | Preview analysis without executing |
--interactive | Interactive package selection |
--fix | Apply auto-fixes where available (placeholder) |
Generate interactive dependency graph visualizations with the visualize command:
# Generate interactive HTML visualization
workspace-analyzer visualize
# Generate JSON data for external tools
workspace-analyzer visualize --format json --output graph.json
# Generate Mermaid diagram
workspace-analyzer visualize --format mermaid --output graph.mmd
# Interactive mode with options
workspace-analyzer visualize --interactive
# Custom title and node limits
workspace-analyzer visualize --title "My Project" --max-nodes 100
# Generate both HTML and JSON
workspace-analyzer visualize --format both
| Option | Description | Default |
|---|---|---|
--output <path> | Output file path | workspace-graph.html |
--format <format> | Output format: html, json, mermaid, both | html |
--no-open | Disable auto-opening in browser | false (opens by default) |
--title <title> | Visualization title | Workspace Dependency Graph |
--max-nodes <number> | Maximum nodes to render (performance) | 1000 |
--include-type-imports | Include type-only imports in graph | false |
--interactive | Interactive mode for options selection | false |
HTML - Self-contained interactive visualization with D3.js:
JSON - Structured data for external tools and custom processing:
{
"nodes": [
{
"id": "src/utils/helpers.ts",
"name": "helpers.ts",
"filePath": "src/utils/helpers.ts",
"packageName": "@myorg/utils",
"layer": "infrastructure",
"importsCount": 5,
"importedByCount": 12,
"isInCycle": false,
"violations": [
{
"id": "v1",
"message": "Layer violation: infrastructure importing from domain",
"severity": "error",
"ruleId": "layer-dependency"
}
],
"highestViolationSeverity": "error"
}
],
"edges": [
{
"source": "src/utils/helpers.ts",
"target": "src/core/types.ts",
"type": "static",
"isInCycle": false
}
],
"cycles": [
{
"id": "cycle-1",
"nodes": ["src/a.ts", "src/b.ts"],
"edges": [
{"from": "src/a.ts", "to": "src/b.ts"},
{"from": "src/b.ts", "to": "src/a.ts"}
],
"length": 2,
"description": "Circular dependency: a.ts → b.ts → a.ts"
}
],
"statistics": {
"totalNodes": 250,
"totalEdges": 380,
"totalCycles": 3,
"nodesByLayer": {
"domain": 50,
"application": 80,
"infrastructure": 120
},
"violationsBySeverity": {
"critical": 0,
"error": 5,
"warning": 15,
"info": 2
},
"packagesAnalyzed": 12,
"filesAnalyzed": 250
},
"metadata": {
"workspacePath": "/path/to/workspace",
"generatedAt": "2025-12-10T00:00:00Z",
"analyzerVersion": "0.1.0"
}
}
Mermaid - Diagram markup for documentation and external rendering:
graph LR
src_utils_helpers_ts["helpers.ts"]:::class-error
src_core_types_ts["types.ts"]:::class-normal
src_utils_helpers_ts --> src_core_types_ts
classDef class-critical fill:#ff4444,stroke:#cc0000,stroke-width:3px,color:#fff
classDef class-error fill:#ff8844,stroke:#cc4400,stroke-width:2px,color:#fff
classDef class-warning fill:#ffcc44,stroke:#ccaa00,stroke-width:2px,color:#000
classDef class-info fill:#4488ff,stroke:#0044cc,stroke-width:1px,color:#fff
classDef class-normal fill:#88ccff,stroke:#0088cc,stroke-width:1px,color:#000
Investigate Circular Dependencies:
# Generate visualization focusing on cycles
workspace-analyzer visualize --title "Circular Dependencies" --output cycles.html
# Export cycle data for CI validation
workspace-analyzer visualize --format json --output cycles.json
# Generate Mermaid diagram for documentation
workspace-analyzer visualize --format mermaid --output cycles.mmd
Analyze Layer Architecture:
# Visualize architectural boundaries with violations highlighted
workspace-analyzer visualize --title "Architecture Review" --output architecture.html
# Focus on specific package scope
workspace-analyzer visualize --title "Core Packages" --output core.html
Performance Analysis:
# Limit visualization to high-impact nodes
workspace-analyzer visualize --max-nodes 200 --output critical-paths.html
# Export JSON for custom metrics calculation
workspace-analyzer visualize --format json --output metrics.json
CI/CD Integration:
# Generate artifacts for PR review
workspace-analyzer visualize --format both --no-open --output build/graph
# Validate no new circular dependencies
workspace-analyzer visualize --format json | jq '.statistics.totalCycles == 0'
The JSON export format is designed for integration with custom analysis pipelines:
import {readFile} from 'node:fs/promises'
const data = JSON.parse(await readFile('graph.json', 'utf-8'))
// Find all files with critical violations
const criticalFiles = data.nodes.filter(
node => node.highestViolationSeverity === 'critical'
)
// Identify largest cycles
const largeCycles = data.cycles
.filter(cycle => cycle.length > 5)
.sort((a, b) => b.length - a.length)
// Calculate dependency metrics
const avgImportsPerFile = data.statistics.totalEdges / data.statistics.totalNodes
const cycleRate = data.statistics.totalCycles / data.statistics.totalNodes
// Detect architectural hotspots
const layerViolations = data.nodes
.filter(node => node.violations.some(v => v.ruleId === 'layer-dependency'))
.map(node => ({
file: node.filePath,
layer: node.layer,
violations: node.violations.length,
}))
.sort((a, b) => b.violations - a.violations)
// Find most connected nodes (potential coupling issues)
const highlyConnected = data.nodes
.filter(node => node.importsCount + node.importedByCount > 20)
.sort((a, b) =>
(b.importsCount + b.importedByCount) - (a.importsCount + a.importedByCount)
)
analyzeWorkspace(path, options)Analyzes an entire workspace for issues.
import {analyzeWorkspace} from '@bfra.me/workspace-analyzer'
const result = await analyzeWorkspace('./my-monorepo', {
minSeverity: 'warning',
categories: ['dependency', 'architecture'],
onProgress: (progress) => {
console.log(`${progress.phase}: ${progress.processed}/${progress.total}`)
},
})
if (result.success) {
console.log(`Found ${result.data.summary.totalIssues} issues`)
for (const issue of result.data.issues) {
console.log(`[${issue.severity}] ${issue.title}`)
console.log(` ${issue.location.filePath}:${issue.location.line}`)
if (issue.suggestion) {
console.log(` Fix: ${issue.suggestion}`)
}
}
} else {
console.error(`Analysis failed: ${result.error.message}`)
}
analyzePackages(path, packageNames, options)Analyzes specific packages within a workspace.
import {analyzePackages} from '@bfra.me/workspace-analyzer'
const result = await analyzePackages('./my-monorepo', [
'@myorg/core',
'@myorg/utils',
])
if (result.success) {
console.log(`Analyzed ${result.data.summary.packagesAnalyzed} packages`)
}
defineConfig(config)Type-safe configuration helper.
import {defineConfig} from '@bfra.me/workspace-analyzer'
export default defineConfig({
minSeverity: 'warning',
categories: ['dependency', 'architecture'],
})
Create a workspace-analyzer.config.ts file in your workspace root:
import {defineConfig} from '@bfra.me/workspace-analyzer'
export default defineConfig({
// File patterns
include: ['**/*.ts', '**/*.tsx'],
exclude: ['**/node_modules/**', '**/lib/**', '**/dist/**'],
// Analysis settings
minSeverity: 'warning',
categories: ['dependency', 'configuration', 'architecture'],
// Performance
cache: true,
cacheDir: '.workspace-analyzer-cache',
concurrency: 4,
// Package patterns (for monorepo scanning)
packagePatterns: ['packages/*', 'apps/*'],
// Per-analyzer configuration
analyzers: {
'circular-import': {enabled: true, severity: 'error'},
'unused-dependency': {enabled: true, severity: 'warning'},
'config-consistency': {enabled: true},
'tree-shaking-blocker': {enabled: true},
'dead-code': {enabled: false}, // Disable specific analyzer
},
// Architectural rules
architecture: {
layers: [
{name: 'domain', patterns: ['**/domain/**'], allowedImports: []},
{name: 'application', patterns: ['**/application/**'], allowedImports: ['domain']},
{name: 'infrastructure', patterns: ['**/infrastructure/**'], allowedImports: ['domain', 'application']},
],
allowBarrelExports: ['**/index.ts'],
enforcePublicApi: true,
},
})
The analyzer searches for configuration in these files (in order):
workspace-analyzer.config.tsworkspace-analyzer.config.jsworkspace-analyzer.config.mjsworkspace-analyzer.config.cjs| Analyzer | Description |
|---|---|
package-json | Validates package.json structure, exports, and scripts |
tsconfig | Checks TypeScript configuration consistency |
eslint-config | Validates ESLint configuration patterns |
build-config | Analyzes tsup/build configuration |
config-consistency | Cross-validates configuration across files |
version-alignment | Checks dependency version consistency across packages |
exports-field | Validates exports field against actual source files |
| Analyzer | Description |
|---|---|
unused-dependency | Detects dependencies declared but not imported |
circular-import | Finds circular import chains using Tarjan's algorithm |
peer-dependency | Validates peer dependency declarations |
duplicate-dependency | Finds duplicate dependencies across packages |
| Analyzer | Description |
|---|---|
architectural | Enforces layer boundaries and import restrictions |
| Analyzer | Description |
|---|---|
tree-shaking-blocker | Detects patterns that prevent tree-shaking |
dead-code | Finds unreachable/unused exports |
duplicate-code | Identifies similar code blocks via AST fingerprinting |
large-dependency | Flags large dependencies that may impact bundle size |
| Category | Description |
|---|---|
configuration | Package.json, tsconfig.json, and build config issues |
dependency | Unused, duplicate, or misversioned dependencies |
architecture | Layer violations, barrel export misuse, public API issues |
performance | Tree-shaking blockers, large dependencies |
circular-import | Circular dependency chains |
unused-export | Exports not used within the workspace |
type-safety | TypeScript configuration issues |
| Level | Description |
|---|---|
info | Informational findings, suggestions for improvement |
warning | Potential issues that should be reviewed |
error | Problems that should be fixed |
critical | Severe issues requiring immediate attention |
Enforces architectural layer boundaries:
defineConfig({
architecture: {
layers: [
{name: 'domain', patterns: ['**/domain/**'], allowedImports: []},
{name: 'application', patterns: ['**/app/**'], allowedImports: ['domain']},
{name: 'infrastructure', patterns: ['**/infra/**'], allowedImports: ['domain', 'application']},
],
},
})
Controls export * usage:
defineConfig({
architecture: {
// Allow barrel exports only in specific files
allowBarrelExports: ['**/index.ts'],
// Or disable barrel exports entirely
// allowBarrelExports: false,
},
})
Enforces explicit public API surface:
defineConfig({
architecture: {
enforcePublicApi: true,
},
})
Colorized terminal output with severity highlighting and file locations.
Machine-readable output for CI integration:
workspace-analyzer --json > report.json
{
"issues": [],
"summary": {
"totalIssues": 5,
"bySeverity": {"warning": 3, "error": 2},
"byCategory": {"dependency": 2, "architecture": 3},
"packagesAnalyzed": 8,
"filesAnalyzed": 150,
"durationMs": 2500
}
}
Human-readable report for documentation or PR comments:
workspace-analyzer --markdown > ANALYSIS.md
The analyzer supports incremental caching for improved performance:
defineConfig({
cache: true,
cacheDir: '.workspace-analyzer-cache',
maxCacheAge: 7 * 24 * 60 * 60 * 1000, // 7 days
hashAlgorithm: 'sha256',
})
Cache is automatically invalidated when:
- name: Run workspace analysis
run: pnpm workspace-analyzer --json > analysis-report.json
- name: Check for errors
run: |
if jq -e '.summary.bySeverity.error > 0' analysis-report.json; then
echo "Analysis found errors"
exit 1
fi
# package.json
{
"lint-staged": {
"*.{ts,tsx}": ["workspace-analyzer --categories dependency,architecture"]
}
}
# Build the package
pnpm --filter @bfra.me/workspace-analyzer build
# Run tests
pnpm --filter @bfra.me/workspace-analyzer test
# Type check
pnpm --filter @bfra.me/workspace-analyzer type-check
MIT © Marcus R. Brown
FAQs
Comprehensive monorepo static analysis for workspace configuration, dependencies, and architecture
The npm package @bfra.me/workspace-analyzer receives a total of 20 weekly downloads. As such, @bfra.me/workspace-analyzer popularity was classified as not popular.
We found that @bfra.me/workspace-analyzer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.

Security News
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.