@ui-entropy/scanner-core 0.2.1 → 0.3.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/README.md CHANGED
@@ -1,15 +1,14 @@
1
1
  # @ui-entropy/scanner-core
2
2
 
3
- > Professional CSS waste detection engine. Find unused classes, reduce bundle sizes, and maintain clean stylesheets.
3
+ > Core CSS waste detection engine for programmatic use. Powers the UI Entropy CLI and dashboard.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@ui-entropy/scanner-core.svg)](https://www.npmjs.com/package/@ui-entropy/scanner-core)
6
- [![License](https://img.shields.io/badge/license-Proprietary-blue.svg)](https://uientropy.com/license)
6
+ [![Tests](https://img.shields.io/badge/tests-79%20passing-brightgreen)]()
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue)]()
7
8
 
8
- ## 🎯 What is UI Entropy?
9
+ This package provides the **core analysis engine** for UI Entropy Scanner. It's designed for programmatic use in Node.js applications, build tools, and custom integrations.
9
10
 
10
- UI Entropy is a **professional developer tool** that scans your codebase to identify unused CSS. Think of it as **SonarQube for your UI** - helping teams maintain code quality, reduce technical debt, and optimize bundle sizes.
11
-
12
- This is the **core scanning engine** used by the UI Entropy CLI and dashboard products.
11
+ **For command-line usage**, see [@ui-entropy/cli](../cli) which includes smart initialization and colored output.
13
12
 
14
13
  ## 🚀 Features
15
14
 
@@ -1,26 +1,44 @@
1
1
  /**
2
- * Duplication Analyzer (Placeholder for v0.3+)
2
+ * Duplication Analyzer
3
3
  *
4
4
  * Analyzes CSS selector duplication and similar styles.
5
- * Currently returns score of 0 (no duplication detected).
5
+ * Detects rules with identical properties that could be consolidated.
6
6
  */
7
7
  import type { Analyzer, AnalyzerContext, AnalyzerResult } from './types.js';
8
8
  export interface DuplicationMetrics {
9
- duplicateSelectors: number;
10
- similarRules: number;
9
+ duplicateRuleGroups: number;
10
+ totalDuplicatedRules: number;
11
11
  duplicationPercentage: number;
12
- potentialSavings: number;
12
+ potentialSavingsBytes: number;
13
+ examples: Array<{
14
+ properties: string;
15
+ selectors: string[];
16
+ count: number;
17
+ }>;
13
18
  }
14
19
  /**
15
- * Duplication Analyzer (v0.3+ feature)
20
+ * Duplication Analyzer
16
21
  *
17
- * Detects duplicate selectors and similar CSS rules.
18
- * Currently a placeholder that returns 0.
22
+ * Detects CSS rules with identical properties.
23
+ * Score = percentage of rules that are duplicates (0-100)
19
24
  */
20
25
  export declare class DuplicationAnalyzer implements Analyzer {
21
26
  name: string;
22
27
  weight: number;
23
- analyze(_context: AnalyzerContext): AnalyzerResult;
28
+ analyze(context: AnalyzerContext): AnalyzerResult;
29
+ /**
30
+ * Extract and normalize CSS properties from a rule
31
+ * Returns sorted array of "property: value" strings
32
+ */
33
+ private normalizeProperties;
34
+ /**
35
+ * Format properties for display (limit length)
36
+ */
37
+ private formatProperties;
38
+ /**
39
+ * Generate actionable recommendations based on duplication score
40
+ */
41
+ private generateRecommendations;
24
42
  }
25
43
  /**
26
44
  * Factory function for creating Duplication analyzer
@@ -1 +1 @@
1
- {"version":3,"file":"duplication.d.ts","sourceRoot":"","sources":["../../src/analyzers/duplication.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,YAAW,QAAQ;IAClD,IAAI,SAAiB;IACrB,MAAM,SAAO;IAEb,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,cAAc;CAuBnD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,mBAAmB,CAEzD"}
1
+ {"version":3,"file":"duplication.d.ts","sourceRoot":"","sources":["../../src/analyzers/duplication.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,WAAW,kBAAkB;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,KAAK,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAQD;;;;;GAKG;AACH,qBAAa,mBAAoB,YAAW,QAAQ;IAClD,IAAI,SAAiB;IACrB,MAAM,SAAO;IAEb,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc;IAyFjD;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAsChC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,mBAAmB,CAEzD"}
@@ -1,39 +1,166 @@
1
1
  /**
2
- * Duplication Analyzer (Placeholder for v0.3+)
2
+ * Duplication Analyzer
3
3
  *
4
4
  * Analyzes CSS selector duplication and similar styles.
5
- * Currently returns score of 0 (no duplication detected).
5
+ * Detects rules with identical properties that could be consolidated.
6
6
  */
7
+ import postcss from 'postcss';
7
8
  /**
8
- * Duplication Analyzer (v0.3+ feature)
9
+ * Duplication Analyzer
9
10
  *
10
- * Detects duplicate selectors and similar CSS rules.
11
- * Currently a placeholder that returns 0.
11
+ * Detects CSS rules with identical properties.
12
+ * Score = percentage of rules that are duplicates (0-100)
12
13
  */
13
14
  export class DuplicationAnalyzer {
14
15
  name = 'Duplication';
15
16
  weight = 0.4; // 40% of overall entropy score
16
- analyze(_context) {
17
- // TODO: Implement duplication detection in v0.3+
18
- // - Find duplicate selectors
19
- // - Detect similar CSS rules (same properties, different selectors)
20
- // - Calculate consolidation opportunities
17
+ analyze(context) {
18
+ const { crawl } = context;
19
+ // Parse CSS files and group by property signature
20
+ const signatureMap = new Map();
21
+ let totalRules = 0;
22
+ for (const cssFile of crawl.cssFiles) {
23
+ try {
24
+ const root = postcss.parse(cssFile.content);
25
+ root.walkRules((rule) => {
26
+ totalRules++;
27
+ // Extract and normalize properties
28
+ const properties = this.normalizeProperties(rule);
29
+ if (!properties || properties.length === 0) {
30
+ return; // Skip rules with no properties
31
+ }
32
+ // Create a signature from sorted properties
33
+ const signature = properties.join(';');
34
+ // Group rules by signature
35
+ if (signatureMap.has(signature)) {
36
+ const existing = signatureMap.get(signature);
37
+ existing.selectors.push(rule.selector);
38
+ existing.bytes += Buffer.byteLength(rule.toString(), 'utf8');
39
+ }
40
+ else {
41
+ signatureMap.set(signature, {
42
+ properties: signature,
43
+ selectors: [rule.selector],
44
+ bytes: Buffer.byteLength(rule.toString(), 'utf8'),
45
+ });
46
+ }
47
+ });
48
+ }
49
+ catch (error) {
50
+ // Skip files that can't be parsed
51
+ continue;
52
+ }
53
+ }
54
+ // Find duplicates (groups with 2+ selectors)
55
+ const duplicates = [];
56
+ let totalDuplicatedRules = 0;
57
+ let potentialSavingsBytes = 0;
58
+ for (const sig of signatureMap.values()) {
59
+ if (sig.selectors.length > 1) {
60
+ duplicates.push(sig);
61
+ totalDuplicatedRules += sig.selectors.length;
62
+ // Savings = (n-1) * bytes per rule (keep one, remove n-1)
63
+ potentialSavingsBytes += ((sig.selectors.length - 1) * sig.bytes) / sig.selectors.length;
64
+ }
65
+ }
66
+ // Calculate duplication percentage
67
+ const duplicationPercentage = totalRules > 0
68
+ ? Math.round((totalDuplicatedRules / totalRules) * 100)
69
+ : 0;
70
+ // Sort duplicates by impact (most duplicated first)
71
+ duplicates.sort((a, b) => b.selectors.length - a.selectors.length);
72
+ // Build metrics
21
73
  const metrics = {
22
- duplicateSelectors: 0,
23
- similarRules: 0,
24
- duplicationPercentage: 0,
25
- potentialSavings: 0,
74
+ duplicateRuleGroups: duplicates.length,
75
+ totalDuplicatedRules,
76
+ duplicationPercentage,
77
+ potentialSavingsBytes: Math.round(potentialSavingsBytes),
78
+ examples: duplicates.slice(0, 5).map(dup => ({
79
+ properties: this.formatProperties(dup.properties),
80
+ selectors: dup.selectors,
81
+ count: dup.selectors.length,
82
+ })),
26
83
  };
84
+ // Generate recommendations
85
+ const recommendations = this.generateRecommendations(duplicationPercentage, duplicates.length);
27
86
  return {
28
87
  name: this.name,
29
- score: 0, // Placeholder: no duplication detected
88
+ score: duplicationPercentage,
30
89
  weight: this.weight,
31
90
  metrics,
32
- recommendations: [
33
- 'Duplication analysis coming in v0.3',
34
- ],
91
+ recommendations,
35
92
  };
36
93
  }
94
+ /**
95
+ * Extract and normalize CSS properties from a rule
96
+ * Returns sorted array of "property: value" strings
97
+ */
98
+ normalizeProperties(rule) {
99
+ const properties = [];
100
+ rule.walkDecls((decl) => {
101
+ // Normalize whitespace and create canonical form
102
+ const prop = decl.prop.trim().toLowerCase();
103
+ const value = decl.value.trim().replace(/\s+/g, ' ');
104
+ properties.push(`${prop}:${value}`);
105
+ });
106
+ // Sort for consistent comparison
107
+ return properties.sort();
108
+ }
109
+ /**
110
+ * Format properties for display (limit length)
111
+ */
112
+ formatProperties(properties) {
113
+ const parts = properties.split(';').filter(Boolean);
114
+ if (parts.length <= 3) {
115
+ return parts.join('; ');
116
+ }
117
+ return `${parts.slice(0, 3).join('; ')}... (+${parts.length - 3} more)`;
118
+ }
119
+ /**
120
+ * Generate actionable recommendations based on duplication score
121
+ */
122
+ generateRecommendations(percentage, groupCount) {
123
+ if (percentage === 0) {
124
+ return [
125
+ 'Excellent! No duplicate CSS rules detected.',
126
+ 'Your styles are well-organized.',
127
+ ];
128
+ }
129
+ else if (percentage < 10) {
130
+ return [
131
+ 'Minimal duplication detected.',
132
+ `Consider consolidating ${groupCount} rule groups with identical properties.`,
133
+ 'Use CSS variables or utility classes for repeated styles.',
134
+ ];
135
+ }
136
+ else if (percentage < 25) {
137
+ return [
138
+ 'Moderate duplication detected.',
139
+ `${groupCount} groups of rules share identical properties.`,
140
+ 'Consolidate duplicate rules into shared classes.',
141
+ 'Consider using a utility-first CSS framework (Tailwind, UnoCSS).',
142
+ ];
143
+ }
144
+ else if (percentage < 50) {
145
+ return [
146
+ 'High duplication: Significant consolidation opportunities.',
147
+ `${groupCount} rule groups could be merged.`,
148
+ 'Extract common patterns into reusable utility classes.',
149
+ 'Consider using CSS-in-JS with style composition.',
150
+ 'Review component styles for shared patterns.',
151
+ ];
152
+ }
153
+ else {
154
+ return [
155
+ 'Critical duplication: Major refactoring recommended.',
156
+ `${groupCount} duplicate rule groups detected.`,
157
+ 'Switch to utility-first CSS (Tailwind, UnoCSS).',
158
+ 'Extract all common styles into utility classes.',
159
+ 'Consider atomic CSS architecture.',
160
+ 'Use design tokens and CSS variables for consistency.',
161
+ ];
162
+ }
163
+ }
37
164
  }
38
165
  /**
39
166
  * Factory function for creating Duplication analyzer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui-entropy/scanner-core",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "CSS waste detection engine - finds unused classes and IDs in your codebase",
6
6
  "main": "./dist/index.js",
package/README.old.md DELETED
@@ -1,263 +0,0 @@
1
- # Scanner Core
2
-
3
- The core CSS waste analysis engine for UI Entropy Scanner.
4
-
5
- ## ✅ What We Built (Days 1-5)
6
-
7
- ### **Complete CSS Waste Detection System**
8
-
9
- A production-ready TypeScript library that scans entire projects and detects unused CSS.
10
-
11
- **Day 1-2: CSS Parsing**
12
- - ✓ Extracts class & ID selectors from stylesheets
13
- - ✓ Supports Bootstrap, Tailwind, custom CSS
14
- - ✓ Handles complex selectors (pseudo-classes, compound, grouped)
15
-
16
- **Day 3: Usage Detection & Analysis**
17
- - ✓ Scans HTML/JSX/Vue/Angular for class usage
18
- - ✓ Compares CSS selectors vs. actual usage
19
- - ✓ Calculates waste percentage
20
- - ✓ Generates detailed reports (JSON + Text)
21
- - ✓ Identifies specific unused selectors
22
-
23
- **Day 4-5: File System Scanner** 🔥
24
- - ✓ Recursive directory scanning with glob patterns
25
- - ✓ Config file support (`.ui-entropy.json`)
26
- - ✓ `.gitignore` integration
27
- - ✓ Automatic CSS/source file detection
28
- - ✓ Complete scan orchestration
29
- - ✓ **Ready for real projects!**
30
-
31
- ### 📊 Test Results
32
-
33
- ```
34
- ✓ 76 tests passing (6 test suites)
35
- ✓ End-to-end scanning validated
36
- ✓ Real directory structure tested
37
- ```
38
-
39
- ## Usage
40
-
41
- ### Scan Any Project (New!)
42
-
43
- ```typescript
44
- import { scan } from '@ui-entropy/scanner-core';
45
-
46
- // Scan entire project directory
47
- const result = scan({
48
- baseDir: '/path/to/your/project',
49
- format: 'text', // or 'json' or 'summary'
50
- });
51
-
52
- console.log(result.report);
53
- // Output:
54
- // 🔍 UI Entropy Analysis Report
55
- // Waste Percentage: 34.4%
56
- // ...
57
-
58
- console.log(result.analysis.unusedClasses);
59
- // Set { 'btn-lg', 'alert-danger', ... }
60
- ```
61
-
62
- ### With Config File
63
-
64
- Create `.ui-entropy.json` in your project root:
65
-
66
- ```json
67
- {
68
- "cssPatterns": ["src/**/*.css", "styles/**/*.scss"],
69
- "sourcePatterns": ["src/**/*.{tsx,ts,jsx,js}"],
70
- "ignorePatterns": ["**/*.test.*"],
71
- "respectGitignore": true,
72
- "thresholds": {
73
- "wastePercentage": 50
74
- }
75
- }
76
- ```
77
-
78
- Then simply:
79
-
80
- ```typescript
81
- import { scan } from '@ui-entropy/scanner-core';
82
-
83
- const result = scan(); // Uses config file + current directory
84
- console.log(result.report);
85
- ```
86
-
87
- ### Complete Analysis Pipeline
88
-
89
- ```typescript
90
- import {
91
- extractSelectors,
92
- extractUsageFromMultiple,
93
- analyzeWaste,
94
- generateTextReport,
95
- } from '@ui-entropy/scanner-core';
96
-
97
- // 1. Extract CSS selectors
98
- const cssContent = fs.readFileSync('styles.css', 'utf-8');
99
- const selectors = extractSelectors(cssContent);
100
-
101
- // 2. Extract usage from source files
102
- const sourceFiles = [
103
- fs.readFileSync('App.tsx', 'utf-8'),
104
- fs.readFileSync('index.html', 'utf-8'),
105
- ];
106
- const usage = extractUsageFromMultiple(sourceFiles);
107
-
108
- // 3. Analyze waste
109
- const analysis = analyzeWaste(selectors, usage);
110
-
111
- // 4. Generate report
112
- console.log(generateTextReport(analysis));
113
- // Output:
114
- // 🔍 UI Entropy Analysis Report
115
- // Waste Percentage: 34.4%
116
- // Estimated Wasted Bytes: 1,411 bytes
117
- // ...
118
- ```
119
-
120
- ### Quick Start
121
-
122
- ```bash
123
- # Run the demo (Days 1-3 features)
124
- pnpm demo
125
-
126
- # Run file scanner demo (Days 4-5)
127
- pnpm scan-demo
128
-
129
- # Run tests
130
- pnpm test
131
-
132
- # Watch mode
133
- pnpm test:watch
134
- ```
135
-
136
- ## Real-World Results
137
-
138
- **Bootstrap + HTML Example:**
139
- - 20 classes defined, 10 used → **45.5% waste** 🚨
140
- - ~1,077 bytes of unused CSS
141
-
142
- **Tailwind + React Example:**
143
- - 38 utility classes, 24 used → **35.9% waste**
144
- - ~621 bytes wasted
145
-
146
- **Multi-Framework Project:**
147
- - 61 selectors total, 40 used → **34.4% waste**
148
- - ~1,411 bytes wasted across Bootstrap + Tailwind
149
-
150
- ## Architecture
151
-
152
- ```
153
- src/
154
- ├── parse-css.ts # CSS selector extraction
155
- ├── extract-usage.ts # Source file scanning (HTML/JSX/Vue)
156
- ├── analyze.ts # Waste calculation engine
157
- ├── report.ts # Report generation (JSON/Text)
158
- ├── crawl.ts # File system scanner (NEW!)
159
- ├── config.ts # Config file support (NEW!)
160
- ├── scan.ts # Scan orchestrator (NEW!)
161
- ├── index.ts # Public API
162
- ├── demo.ts # Interactive demo
163
- ├── scan-demo.ts # File scanner demo (NEW!)
164
- ├── *.test.ts # Comprehensive tests (76 tests)
165
- └── test-fixtures/
166
- ├── bootstrap-sample.css
167
- ├── tailwind-sample.css
168
- ├── sample.html
169
- ├── sample.tsx
170
- └── sample.vue
171
- ```
172
-
173
- ## Supported Frameworks
174
-
175
- ### CSS Frameworks
176
- - Bootstrap
177
- - Tailwind
178
- - Custom CSS
179
- - Any PostCSS-compatible stylesheet
180
-
181
- ### Template Languages
182
- - HTML
183
- - JSX/TSX (React)
184
- - Vue templates
185
- - Angular templates
186
- - Basic support for `clsx`, `classnames` utilities
187
-
188
- ## API Reference
189
-
190
- ### CSS Extraction
191
- ```typescript
192
- extractSelectors(cssText: string): ExtractedSelectors
193
- extractSelectorsFromMultiple(cssFiles: string[]): ExtractedSelectors
194
- ```
195
-
196
- ### Usage Detection
197
- ```typescript
198
- extractUsage(sourceText: string): { classes: Set<string>, ids: Set<string> }
199
- extractUsageFromMultiple(sourceFiles: string[]): UsageExtractionResult
200
- ```
201
-
202
- ### Analysis
203
- ```typescript
204
- analyzeWaste(selectors: ExtractedSelectors, usage: UsageExtractionResult): AnalysisResult
205
- estimateWastedBytes(analysis: AnalysisResult): number
206
- ```
207
-
208
- ### Reporting
209
- ```typescript
210
- generateReport(analysis: AnalysisResult, format: 'json' | 'text' | 'summary'): string
211
- generateJsonReport(analysis: AnalysisResult): JsonReport
212
- generateTextReport(analysis: AnalysisResult): string
213
- generateSummaryReport(analysis: AnalysisResult): string
214
- ```
215
-
216
- ### File System (NEW!)
217
- ```typescript
218
- scan(options?: ScanOptions): ScanResult
219
- quickScan(baseDir?: string): string
220
- crawl(options: CrawlOptions): Promise<CrawlResult>
221
- crawlSync(options: CrawlOptions): CrawlResult
222
- ```
223
-
224
- ### Configuration (NEW!)
225
- ```typescript
226
- loadConfig(baseDir?: string): Config
227
- getConfig(baseDir?: string): Config
228
- ```
229
-
230
- ## Next Steps (Week 2)
231
-
232
- **Day 6-7: CLI Development**
233
- - [ ] Build `ui-entropy` CLI command
234
- - [ ] Progress indicators & spinners
235
- - [ ] Colored terminal output
236
- - [ ] Watch mode for development
237
- - [ ] Exit codes based on thresholds
238
- - [ ] CI/CD integration support
239
-
240
- **Week 3: GitHub Integration**
241
- - [ ] GitHub App authentication
242
- - [ ] Automated PR comments
243
- - [ ] Trend tracking over time
244
- - [ ] Badge generation
245
-
246
- ## Tech Stack
247
-
248
- - **TypeScript** - Type safety & developer experience
249
- - **PostCSS** - Industry-standard CSS parsing
250
- - **Vitest** - Fast, modern testing
251
- - **tsx** - TypeScript execution
252
-
253
- ## Why This Matters
254
-
255
- This engine is the **foundation** for:
256
- - ✅ **Scan any project** - Works on real codebases today!
257
- - ✅ CLI tool (coming Days 6-7)
258
- - ✅ GitHub integration (automated PR comments)
259
- - ✅ SaaS dashboard (continuous monitoring)
260
- - ✅ Real-time waste alerts
261
-
262
- **Current State:** Fully functional scanner - **ready for production use!**
263
- **Next Milestone:** CLI tool with colored output, watch mode, CI/CD integration