npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

uipool

v0.3.0

Published

CLI tool to scan repositories for UI pattern annotations and generate usage reports

Readme

UiPool CLI

A CLI tool to scan repositories for UI pattern and component annotations and generate usage reports. Supports React, Angular, Vue, and other modern web frameworks.

Installation

# Install globally
npm install -g uipool

# Or use with npx
npx uipool scan

Usage

Basic Scan (v0.3.0 — "Magical" Defaults)

Scan the current directory and generate a full insights report:

uipool scan

As of v0.3.0, scan includes auto-detection and usage analysis by default. This will:

  1. Scan all supported files in the current directory
  2. Extract pattern annotations from comments (// uipool-pattern: ...)
  3. Auto-detect components by folder structure (no annotations required)
  4. Analyze usage to find where components are imported
  5. Generate rich insights: top used, unused, pattern suggestions, clusters
  6. Write uipool-report.json to the current directory

To disable auto-detection or usage analysis, use --no-auto or --no-usage.

Options

uipool scan [options]

Options:
  -r, --root <path>              Directory to scan (default: current directory)
  -o, --out <path>               Output JSON file path (default: <root>/uipool-report.json)
  -p, --project <name>           Override project name (default: inferred from package.json)
  -e, --ext <list>               Comma-separated file extensions to scan
  -i, --ignore <list>            Comma-separated ignore globs to append to defaults
  --strict                       Only accept namespaced markers (uipool-pattern, uipool-component)
  --warn-legacy                  Warn about legacy pattern: annotations (default: true)
  --no-warn-legacy               Suppress warnings about legacy pattern: annotations
  --auto                         Auto-scan mode: discover components by folder name (default: true)
  --no-auto                      Disable auto-scan mode (only detect tagged annotations)
  --usage                        Detect component usage across the codebase (default: true)
  --no-usage                     Disable usage detection
  --fail-on-unused               Exit with code 1 if unused components are found
  --summary-json                 Output a one-line JSON summary to stdout (CI-friendly)
  --max-depth <n>                Maximum directory depth for scanning (auto mode)
  --cluster-min-components <n>   Min components per cluster (default: 1)
  --cluster-min-files <n>        Min files per cluster (default: 1)
  --cluster-max <n>              Max clusters in output (default: 200)
  --top-used <n>                 Number of top used components to include (default: 20)

Examples

# Scan a specific directory
uipool scan --root ./src

# Custom output path
uipool scan --out ./reports/patterns.json

# Override project name
uipool scan --project "My App"

# Scan only TypeScript and Vue files
uipool scan --ext .ts,.vue

# Add custom ignore patterns
uipool scan --ignore "**/legacy/**,**/deprecated/**"

# Strict mode - only namespaced annotations
uipool scan --strict

# Suppress legacy warnings
uipool scan --no-warn-legacy

Auto-Scan Mode (Default in v0.3.0)

Auto-scan discovers components automatically by folder structure, without requiring annotations. Combined with usage detection, it generates rich insights.

As of v0.3.0, auto-scan and usage detection are enabled by default. Simply run:

uipool scan -r ./app

To customize or tune the output:

# Full insights with cluster tuning
uipool scan \
  --cluster-min-components 2 \
  --cluster-min-files 2 \
  --top-used 10 \
  -r ./app

# Fail CI if unused components exist
uipool scan --fail-on-unused -r ./app

# Disable auto-scan (only tagged patterns/components)
uipool scan --no-auto --no-usage -r ./app

What auto-scan provides:

  • Components: Discovers Vue/React/Angular components by folder naming conventions
  • Usage detection: Tracks where each component is imported/used across your codebase
  • Candidate patterns: Suggests pattern groupings based on folder structure
  • Usage clusters: Groups components by where they're used together (route-based)
  • Top used: Ranks components by usage frequency
  • Unused detection: Identifies components with no detected imports
  • Risk signals: Flags potential issues (e.g., high unused ratio)

CI-Friendly JSON Summary

Use --summary-json to output a compact one-line JSON summary for CI pipelines:

# Auto-scan with usage detection and JSON summary
uipool scan --auto --usage --summary-json -r ./app -o report.json

This prints a single JSON line to stdout containing:

{
  "version": "0.3.0",
  "mode": "auto",
  "root": "./app",
  "projectName": "app",
  "generatedAt": "2026-01-13T12:00:00.000Z",
  "filesScanned": 83,
  "totalComponents": 15,
  "unusedComponents": 2,
  "unusedPercent": 13.3,
  "totalCandidatePatterns": 3,
  "totalUsageClusters": 9,
  "topClusters": [
    { "clusterId": "pages/docs", "componentCount": 4, "fileCount": 14 }
  ],
  "topUnused": ["copy-code", "preview-mode-banner"],
  "riskSignals": ["unused-components-found"],
  "reportPath": "./app/uipool-report.json",
  "reportWritten": true,
  "exitCodeHint": 0,
  "flags": {
    "auto": true,
    "usage": true,
    "failOnUnused": false,
    "summaryJson": true
  }
}

Summary fields:

| Field | Description | | --------------- | ------------------------------------------------------------------------ | | reportPath | Normalized path to the written report file (forward slashes) | | reportWritten | true if report was written successfully, false if write failed | | exitCodeHint | Expected exit code: 1 if --fail-on-unused and unused exist, else 0 |

When --summary-json is enabled:

  • Normal verbose console output is suppressed
  • Exactly one line of JSON is printed to stdout
  • The full report is still written to the output file

With --fail-on-unused: The summary is printed before exiting with code 1 if unused components exist:

uipool scan --auto --usage --summary-json --fail-on-unused -r ./app
# Prints JSON summary, then exits with code 1 if unused components found

Annotation Formats

UiPool supports two types of annotations: patterns and components.

Pattern Annotations (Recommended)

Use the namespaced uipool-pattern: annotation for future-proof scanning:

// uipool-pattern: login-flow
function LoginPage() { ... }

/* uipool-pattern: data-table */
const TableComponent = ...
# uipool-pattern: user-dashboard
class DashboardView:
    pass

Legacy Pattern Annotations

For backward compatibility, the original pattern: annotation is still supported:

// pattern: login-flow
function LoginPage() { ... }

Note: We recommend migrating to uipool-pattern: for future-proof scanning. Use --strict mode to enforce namespaced annotations only.

Component Annotations (Optional)

Track component usage with uipool-component::

// uipool-component: button-primary
export const PrimaryButton = () => { ... }

/* uipool-component: modal-dialog */
export function ModalDialog() { ... }

Components will appear in a separate components array in the report, enabling pattern-to-component mapping in UiPool.

HTML/Angular Template Annotations

For Angular templates and HTML files, use HTML comments:

<!-- uipool-pattern: login-flow -->
<div class="login-container">
  <!-- uipool-component: input-field -->
  <input type="email" />

  <!-- uipool-component: button-primary -->
  <button type="submit">Sign In</button>
</div>

Supported Comment Syntaxes

| Syntax | Languages | | -------------- | ------------------------------------------------- | | // ... | JavaScript, TypeScript, JSX, TSX, CSS, SCSS, LESS | | /* ... */ | JavaScript, TypeScript, CSS, SCSS, LESS, Vue | | # ... | Markdown, Python, YAML | | <!-- ... --> | HTML, Vue templates, Angular templates, MDX |

Flexible Whitespace

Extra spaces are allowed in all formats:

//   uipool-pattern:    login-flow
/*   uipool-component:   button-primary   */
<!--   uipool-pattern:   login-flow   -->

Case Insensitive

The annotation keywords are case-insensitive:

// uipool-pattern: login-flow
// UIPOOL-PATTERN: login-flow
// UiPool-Pattern: login-flow

ID Format

Pattern and component IDs can contain:

  • Letters (a-z, A-Z)
  • Numbers (0-9)
  • Dashes (-)
  • Underscores (_)

Examples: login-flow, data_table, UserDashboard, form-wizard-v2, button-primary

Output Format

The generated report follows this structure:

{
  "generatedAt": "2026-01-13T21:43:49.381Z",
  "projectName": "MyApp",
  "entries": [
    {
      "patternId": "login-flow",
      "count": 4,
      "files": ["app/pages/auth/login.vue", "app/pages/index.vue"]
    }
  ],
  "components": [
    {
      "componentId": "button-primary",
      "count": 2,
      "files": ["src/components/Button.tsx"],
      "usedCount": 5,
      "usedInFiles": ["src/App.tsx", "src/Dashboard.tsx"],
      "unused": false,
      "usageSignals": {
        "importRefs": 3,
        "templateTagRefs": 5,
        "dynamicImportRefs": 0,
        "registryRefs": 0,
        "globalRegRefs": 0
      }
    },
    {
      "componentId": "deprecated-widget",
      "count": 1,
      "files": ["src/components/DeprecatedWidget.tsx"],
      "usedCount": 0,
      "usedInFiles": [],
      "unused": true,
      "unusedReason": "No imports, template usage, or dynamic references detected",
      "usageSignals": {
        "importRefs": 0,
        "templateTagRefs": 0,
        "dynamicImportRefs": 0,
        "registryRefs": 0,
        "globalRegRefs": 0
      }
    }
  ],
  "candidatePatterns": [
    {
      "patternId": "auth",
      "componentIds": ["login-form", "signup-form"],
      "files": [
        "components/auth/LoginForm.vue",
        "components/auth/SignupForm.vue"
      ],
      "count": 2,
      "source": "folder",
      "rationale": "Components grouped by auth/ folder"
    },
    {
      "patternId": "co-usage-1",
      "componentIds": ["data-table", "pagination", "filter-bar"],
      "files": ["pages/users.vue", "pages/orders.vue"],
      "count": 3,
      "source": "coUsage",
      "confidence": 0.85,
      "rationale": "Strong correlation: components frequently co-occur"
    }
  ],
  "usageClusters": [
    {
      "clusterId": "pages/auth",
      "componentIds": ["login-form", "auth-header"],
      "files": ["pages/auth/login.vue", "pages/auth/signup.vue"],
      "componentCount": 2,
      "fileCount": 2
    }
  ],
  "topUsedComponents": [
    {
      "componentId": "base-button",
      "usedCount": 42,
      "usedInFiles": ["src/App.vue", "src/Dashboard.vue"]
    }
  ],
  "unusedSummary": {
    "totalComponents": 15,
    "unusedCount": 2,
    "unusedPercent": 13.3
  },
  "unusedByGroup": [
    {
      "groupId": "legacy",
      "unusedCount": 2,
      "componentIds": ["old-button", "old-card"]
    }
  ],
  "highlightClusters": [
    {
      "clusterId": "pages/docs",
      "componentIds": ["docs-header", "docs-section"],
      "componentCount": 4,
      "fileCount": 14,
      "rationale": "Shared set powering a route group"
    }
  ],
  "riskSignals": [
    {
      "type": "unused-components-found",
      "message": "2 unused components detected",
      "componentIds": ["old-button", "old-card"]
    }
  ]
}

Core Fields

| Field | Description | | --------------------------- | ---------------------------------------------------------------- | | generatedAt | ISO 8601 timestamp of when the report was generated | | projectName | Name of the project (from package.json or folder name) | | entries | Array of pattern entries, sorted alphabetically by patternId | | entries[].patternId | The pattern identifier | | entries[].count | Total number of occurrences across all files | | entries[].files | Unique list of files containing the pattern | | components | Array of component entries (from --auto mode or annotations) | | components[].componentId | The component identifier | | components[].source | "tagged" (via comment) or "auto" (folder detection) (v0.3.0) | | components[].count | Total number of occurrences across all files | | components[].files | Unique list of files containing the component | | components[].usedCount | Number of files where component is used (with --usage) | | components[].usedInFiles | Files where component is imported/used (with --usage) | | components[].unused | true if component has no detected usage (with --usage) | | components[].usageSignals | Detailed usage signal counts (v0.3.1) | | components[].unusedReason | Human-readable explanation when unused=true (v0.3.1) |

Usage Signals (v0.3.1)

Each component includes a usageSignals object with detailed detection counts:

| Signal | Description | | ------------------- | ------------------------------------------------------------------ | | importRefs | Explicit import statements (default/named imports) | | templateTagRefs | Template usage (<MyComp> or <my-comp>) | | dynamicImportRefs | Dynamic imports (import('./MyComp.vue'), defineAsyncComponent) | | registryRefs | Component registry references (components: { MyComp }) | | globalRegRefs | Global registrations (app.component(), resolveComponent()) |

Unused detection logic: A component is marked unused=true only if ALL signals are 0 AND usedInFiles is empty. This multi-signal approach reduces false positives from dynamic components, auto-imports, or global registrations.

Insight Fields (v0.3.0)

These fields are included when using --auto --usage mode:

| Field | Description | | ---------------------------------- | ------------------------------------------------------------------ | | candidatePatterns | Suggested pattern groupings based on folder structure and co-usage | | candidatePatterns[].patternId | Suggested pattern name (from folder or cluster ID) | | candidatePatterns[].componentIds | Components that would belong to this pattern | | candidatePatterns[].source | "folder" or "coUsage" (v0.3.1) | | candidatePatterns[].confidence | Confidence score 0-1 for coUsage patterns (v0.3.1) | | candidatePatterns[].rationale | Human-readable explanation (v0.3.1) | | usageClusters | Groups of components used together in the same files | | usageClusters[].clusterId | Cluster identifier (typically a route/page path) | | usageClusters[].componentIds | Components used in this cluster | | usageClusters[].componentCount | Number of components in the cluster | | usageClusters[].fileCount | Number of files in the cluster | | topUsedComponents | Most frequently used components (limit: --top-used) | | unusedSummary | Summary of unused component statistics | | unusedSummary.totalComponents | Total number of components scanned | | unusedSummary.unusedCount | Number of unused components | | unusedSummary.unusedPercent | Percentage of components that are unused | | unusedByGroup | Unused components grouped by folder | | highlightClusters | Notable clusters with high component reuse | | highlightClusters[].rationale | Why this cluster is highlighted | | riskSignals | Actionable warnings about codebase health | | riskSignals[].type | Signal type (e.g., unused-components-found) | | riskSignals[].message | Human-readable description |

Note: Insight fields are only populated when using --auto --usage mode. They enable the Insights tab in the UiPool web dashboard.

Default Behavior

File Extensions

By default, these extensions are scanned:

  • .js - JavaScript
  • .ts - TypeScript
  • .vue - Vue components
  • .jsx - React JSX
  • .tsx - React TypeScript
  • .md - Markdown
  • .html - HTML / Angular templates
  • .css - CSS
  • .scss - SCSS
  • .sass - Sass
  • .less - Less
  • .mdx - MDX

Ignored Directories

These directories are ignored by default:

  • node_modules
  • dist
  • build
  • .output
  • .nuxt
  • .next
  • .git
  • coverage
  • .turbo
  • .cache

Framework Examples

React

// uipool-pattern: user-profile
// uipool-component: avatar
export function UserProfile({ user }) {
  return (
    <div className="profile">
      <Avatar src={user.avatar} />
      <h1>{user.name}</h1>
    </div>
  );
}

Angular

<!-- user-list.component.html -->
<!-- uipool-pattern: user-list -->
<div class="user-list">
  <!-- uipool-component: user-card -->
  <app-user-card *ngFor="let user of users" [user]="user" />
</div>

Vue

<template>
  <!-- uipool-pattern: dashboard -->
  <div class="dashboard">
    <!-- uipool-component: stats-widget -->
    <StatsWidget :data="stats" />
  </div>
</template>

<script setup>
// uipool-pattern: dashboard
import StatsWidget from "./StatsWidget.vue";
</script>

Integration with UiPool

Upload the generated uipool-report.json to UiPool to:

  • Track pattern usage across your codebase
  • Map components to patterns
  • Identify unused or deprecated patterns
  • Generate documentation coverage reports
  • Share usage analytics with your team

License

MIT