I've been working on a CLI tool called UIQuarter that does static analysis on UI codebases. It uses AST parsing to understand component structures, map dependencies, detect styling patterns, and find architectural issues. Then it can generate context files for AI coding tools, but the analysis itself is useful on its own.
I wanted to write about what the tool actually detects and how, since "static analysis for UI codebases" is pretty vague.
What it analyzes
UIQuarter has 20 analyzers. When you run uiquarter init on a project, here's what happens under the hood.
Component detection
The ComponentAnalyzer uses ts-morph to parse the AST of every file. For React, it finds functional components by looking for functions that return JSX. For each one it extracts:
- Component name and file path
- Props (with TypeScript types if available)
- Hooks used (
useState,useEffect, custom hooks) - Whether it's a default or named export
On Vue it parses Single File Components — <script setup> and Options API. On Svelte it parses .svelte files. Angular gets special treatment for decorators (@Component, @Injectable, etc.).
The point isn't just listing files. It's understanding what each component is — what it accepts, what it depends on, where it lives.
Dependency graph
The DependencyAnalyzer builds a graph with typed edges:
- Render edges: Component A renders Component B in its JSX
- Hook edges: Component A uses a hook exported from module B
- HOC edges: Component A is wrapped by a higher-order component from B
- Provider edges: Component A provides context consumed by Component B
This graph is what powers the query commands:
uiquarter query deps Dashboard # what Dashboard depends on
uiquarter query dependents Button # everything that renders Button
uiquarter query hubs # most-connected components
uiquarter query chains # deepest dependency chains
Hub components are interesting — they're the nodes with the highest connectivity. Everything depends on them, so they're risky to change. UIQuarter flags these as architectural insights.
Styling patterns
The StylingAnalyzer detects which approach your project uses:
-
Tailwind — reads your
tailwind.config.jsto understand custom classes. Captures the actual tokens used in the codebase:bg-[#0A0A10],rounded-2xl,text-[#B4A5BD]. Not just "this project uses Tailwind." -
CSS Modules — maps which
.module.cssfile belongs to which component - styled-components / Emotion — detects template literal styling
- Plain CSS — tracks stylesheet imports
This matters for AI context generation. When an AI tool knows your project uses rounded-2xl bg-[#0A0A10] border border-white/10 for cards, it generates matching code instead of rounded-lg bg-gray-800.
UX patterns
The UxAnalyzer checks each component for:
- Error states (try/catch, error boundaries, error message rendering)
- Loading states (spinner rendering, skeleton UIs, loading flags)
- Empty states (zero-data handling, empty list messages)
- Accessibility (ARIA labels, roles, keyboard handlers, focus management)
- Responsive patterns (media queries, responsive class variants)
This is per-component data. So you can see that DataTable handles loading and empty states but UserCard doesn't have error handling.
Naming and structure
The FileStructureAnalyzer extracts:
- File naming convention (PascalCase, kebab-case, camelCase)
- Directory roles (what lives in
pages/vscomponents/vshooks/vslib/) - Barrel exports (index files that re-export)
- Import alias patterns (
@/components/...) - Co-location patterns (test files next to source, styles next to components)
Architecture insights
The InsightEngine processes all analyzer results and detects:
- Hub components — high connectivity, many dependents. Risky to refactor.
- Orphan components — nothing renders them. Dead code candidates.
- Circular dependencies — A imports B imports A.
- Deep chains — A → B → C → D → E. Long dependency paths.
- Missing barrel exports — directories without index files.
- Naming inconsistencies — mixed conventions in the same directory.
Framework-specific analyzers
7 framework analyzers handle framework-specific patterns:
- Next.js — pages vs app router, API routes, middleware, layouts, server/client components
- Nuxt — pages, composables, server routes, middleware
- SvelteKit — routes, load functions, server endpoints
- Angular — components, services, modules, directives, pipes, routes
- Solid — signals, effects, resources, stores
- Lit — custom elements, shadow DOM, reactive properties
- Qwik — resumable components, server functions
Backend analyzers
4 analyzers for backend patterns:
- API routes — Express, Fastify, NestJS, Hono, tRPC, GraphQL endpoint detection
- Database — Prisma, TypeORM, Drizzle, Sequelize, Mongoose model detection
- Auth — JWT, sessions, OAuth, guards, RBAC patterns
- Env config — .env parsing, secret detection, validation patterns
The analysis output
Everything goes into a .uiq/ directory:
.uiq/
index.json # master intelligence index
meta.json # timestamps, stats, build hash
insights.json # architectural issues
snapshot.json # baseline for drift detection
cache/ # analyzer result cache (SHA-256)
patterns/ # per-pattern detail files
The index is a structured JSON with every component, edge, convention, pattern, and insight. You can query it directly or use it to generate context files.
AI context generation
This is the part that connects the analysis to AI coding tools.
uiquarter generate --target all
This reads the analysis index and produces:
| Target | File | Tool |
|---|---|---|
| claude | CLAUDE.md | Claude Code |
| codex | AGENTS.md | OpenAI Codex |
| cursor | .cursorrules | Cursor |
| windsurf | .windsurfrules | Windsurf |
| cline | .clinerules | Cline |
| copilot | copilot-instructions.md | GitHub Copilot |
| aider | CONVENTIONS.md | Aider |
Each file is formatted for the specific tool's conventions. The content includes component maps, dependency relationships, styling tokens, naming conventions, and architecture warnings — compressed from the full analysis.
Real numbers
On a React + Tailwind project (11 key files, 71,322 chars of source code):
71,322 characters compressed to 1,299 characters of structured context. 55x compression ratio. The AI reads one file instead of twelve and gets accurate information about every component, dependency, and convention.
Other features
Beyond analysis and context generation:
Task resolver — fuzzy match a description to relevant files:
uiquarter resolve "add dark mode toggle"
# returns scored list of files that are likely relevant
Uses an inverted index with synonym expansion and fuzzy matching.
Drift detection — track architectural changes over time:
uiquarter drift --save # save current state as baseline
uiquarter drift # compare current vs baseline
# Patterns: 53 → 58 (+5)
# Insights: 5 → 7 (+2 new)
CI/CD integration:
uiquarter ci --fail-on warning
uiquarter ci --pr 42 --repo owner/repo # posts as PR comment
uiquarter ci --template # generates GitHub Action
Convention linting:
uiquarter lint
# checks: file-naming, barrel-exports, circular-deps,
# max-nesting-depth, single-styling, min-accessibility
MCP server for real-time AI tool integration:
uiquarter serve # stdio
uiquarter serve --transport http --port 3100 # HTTP
Exposes tools like uiq_scope_context, uiq_query_component, uiq_resolve_task, uiq_find_insights.
HTML dashboard:
uiquarter report --open
# generates self-contained HTML with dependency graphs and tables
Tech
- TypeScript (strict mode)
- ts-morph for AST parsing
- SHA-256 caching with analyzer versioning
- Commander for CLI
- tsup for dual ESM + CJS builds
- 500+ tests across 36 test files
- Zero external runtime dependencies
- Node.js >= 18
Links
- GitHub: github.com/fuatkeles/uiquarter
- npm:
npm install -g uiquarter - Website: uiquarter.com
- MIT licensed
If you work on UI projects with AI tools, give it a try. If you have ideas for what else the analyzers should detect, I'd like to hear about it.


Top comments (0)