@sfdxy/mule-lint 1.5.2 → 1.6.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
@@ -49,12 +49,22 @@ flowchart TB
49
49
  I[Table]
50
50
  J[JSON]
51
51
  K[SARIF]
52
+ L[HTML Dashboard]
53
+ M[CSV]
54
+ end
55
+
56
+ subgraph HTMLStack["HTML Report Stack"]
57
+ L --> N[Tailwind CSS]
58
+ L --> O[Chart.js]
59
+ L --> P[Tabulator]
52
60
  end
53
61
 
54
62
  A --> B
55
63
  D --> I
56
64
  D --> J
57
65
  D --> K
66
+ D --> L
67
+ D --> M
58
68
  ```
59
69
 
60
70
  ### Data Flow
@@ -259,9 +269,17 @@ Machine-readable for scripting:
259
269
  }
260
270
  ```
261
271
 
262
- ### HTML (Human Readable)
272
+ ### HTML (Interactive Dashboard)
273
+
274
+ Generates a modern, interactive single-page report with:
275
+
276
+ - **Dashboard View**: Summary cards, severity donut chart, top violated rules bar chart, issues by category
277
+ - **Issues Browser**: Full-width searchable table with multiselect filters
278
+ - **Frozen Headers**: Table header stays visible when scrolling
279
+ - **Export**: Download filtered results as CSV
280
+ - **Responsive**: Works on desktop and mobile
263
281
 
264
- Generates a visual report with summary cards and correct issue highlighting:
282
+ Built with **Tailwind CSS**, **Chart.js**, and **Tabulator**.
265
283
 
266
284
  ```bash
267
285
  mule-lint src/main/mule -f html -o report.html
@@ -1,6 +1,6 @@
1
1
  import { LintReport } from '../types/Report';
2
2
  /**
3
- * Format lint report as a modern, interactive HTML page
3
+ * Format lint report as a modern, interactive HTML Single Page Application
4
4
  */
5
5
  export declare function formatHtml(report: LintReport): string;
6
6
  //# sourceMappingURL=HtmlFormatter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HtmlFormatter.d.ts","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAkXrD"}
1
+ {"version":3,"file":"HtmlFormatter.d.ts","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA8lBrD"}
@@ -1,386 +1,612 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatHtml = formatHtml;
4
+ const rules_1 = require("../rules");
4
5
  /**
5
- * Format lint report as a modern, interactive HTML page
6
+ * Format lint report as a modern, interactive HTML Single Page Application
6
7
  */
7
8
  function formatHtml(report) {
8
- const title = 'Mule-Lint Report';
9
- const date = new Date(report.timestamp).toLocaleString();
10
- // Calculate stats
11
- const totalErrors = report.summary.bySeverity.error;
12
- const totalWarnings = report.summary.bySeverity.warning;
13
- const totalInfos = report.summary.bySeverity.info;
14
- const totalIssues = totalErrors + totalWarnings + totalInfos;
15
- // Collect all issues into a flat list for the table
16
- const allIssues = [];
17
- for (const file of report.files) {
18
- if (!file.parsed) {
19
- allIssues.push({
20
- severity: 'error',
21
- file: file.relativePath,
22
- line: 1,
23
- column: 1,
24
- message: file.parseError || 'Failed to parse XML file',
25
- ruleId: 'PARSE-ERROR'
26
- });
27
- continue;
28
- }
29
- for (const issue of file.issues) {
30
- allIssues.push({
31
- severity: issue.severity,
32
- file: file.relativePath,
33
- line: issue.line,
34
- column: issue.column || 0,
35
- message: issue.message,
36
- ruleId: issue.ruleId
37
- });
38
- }
39
- }
9
+ // 1. Enrich Data
10
+ const enrichedFiles = report.files.map(file => ({
11
+ ...file,
12
+ issues: file.issues.map(issue => {
13
+ const ruleDef = rules_1.ALL_RULES.find(r => r.id === issue.ruleId);
14
+ return {
15
+ ...issue,
16
+ category: ruleDef?.category || 'General',
17
+ ruleDescription: ruleDef?.description || 'No description available',
18
+ ruleName: ruleDef?.name || issue.ruleId,
19
+ file: file.relativePath
20
+ };
21
+ })
22
+ }));
23
+ // Reconstruct report data for the client
24
+ const clientData = {
25
+ metadata: {
26
+ timestamp: report.timestamp,
27
+ version: '1.0.0',
28
+ filesScanned: report.files.length,
29
+ duration: 0
30
+ },
31
+ summary: report.summary,
32
+ files: enrichedFiles,
33
+ rules: rules_1.ALL_RULES.map(r => ({ id: r.id, name: r.name, category: r.category, severity: r.severity }))
34
+ };
35
+ const jsonPayload = JSON.stringify(clientData).replace(/</g, '\\u003c');
40
36
  return `<!DOCTYPE html>
41
- <html lang="en">
37
+ <html lang="en" class="bg-gray-50 text-slate-800">
42
38
  <head>
43
39
  <meta charset="UTF-8">
44
40
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
45
- <title>${title}</title>
46
- <style>
47
- :root {
48
- --primary: #00A1DF; /* MuleSoft Blue */
49
- --primary-dark: #0077A5;
50
- --success: #4CAF50;
51
- --error: #F44336;
52
- --warning: #FF9800;
53
- --info: #2196F3;
54
- --surface: #ffffff;
55
- --background: #f4f6f8;
56
- --text-primary: #172b4d;
57
- --text-secondary: #6b778c;
58
- --border: #dfe1e6;
59
- --shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
41
+ <title>Mule-Lint Report</title>
42
+
43
+ <!-- Fonts -->
44
+ <link rel="preconnect" href="https://fonts.googleapis.com">
45
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
46
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
47
+
48
+ <!-- Tailwind CSS -->
49
+ <script src="https://cdn.tailwindcss.com"></script>
50
+ <script>
51
+ tailwind.config = {
52
+ theme: {
53
+ extend: {
54
+ fontFamily: {
55
+ sans: ['Inter', 'sans-serif'],
56
+ mono: ['JetBrains Mono', 'monospace'],
57
+ },
58
+ colors: {
59
+ brand: {
60
+ 50: '#f0f9ff',
61
+ 100: '#e0f2fe',
62
+ 500: '#0ea5e9',
63
+ 600: '#0284c7',
64
+ 900: '#0c4a6e',
65
+ },
66
+ severity: {
67
+ error: '#ef4444',
68
+ warning: '#f59e0b',
69
+ info: '#3b82f6'
70
+ }
71
+ }
72
+ }
73
+ }
60
74
  }
75
+ </script>
76
+
77
+ <!-- Icons -->
78
+ <script src="https://unpkg.com/lucide@latest"></script>
61
79
 
62
- body {
63
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
64
- margin: 0;
65
- padding: 0;
66
- background-color: var(--background);
67
- color: var(--text-primary);
68
- line-height: 1.6;
69
- }
80
+ <!-- Chart.js -->
81
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
82
+
83
+ <!-- Tabulator -->
84
+ <link href="https://unpkg.com/tabulator-tables@6.2.1/dist/css/tabulator.min.css" rel="stylesheet">
85
+ <script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
70
86
 
71
- /* Layout */
72
- .container {
73
- width: 95%; /* Full width as requested */
74
- margin: 0 auto;
75
- padding: 20px;
76
- }
87
+ <style>
88
+ /* Custom Scrollbar */
89
+ ::-webkit-scrollbar { width: 8px; height: 8px; }
90
+ ::-webkit-scrollbar-track { background: transparent; }
91
+ ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
92
+ ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
77
93
 
78
- /* Header */
79
- header {
80
- background-color: var(--surface);
81
- padding: 1rem 0;
82
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
83
- margin-bottom: 2rem;
84
- position: sticky;
85
- top: 0;
86
- z-index: 100;
87
- }
88
- .header-content {
89
- display: flex;
90
- justify-content: space-between;
91
- align-items: center;
94
+ /* Tabulator Overrides */
95
+ .tabulator {
96
+ border: none !important;
97
+ background-color: transparent !important;
98
+ font-family: 'Inter', sans-serif !important;
92
99
  }
93
- h1 { margin: 0; color: var(--primary); font-size: 1.5rem; display: flex; align-items: center; gap: 10px; }
94
- .meta { color: var(--text-secondary); font-size: 0.9em; }
95
-
96
- /* Dashboard Grid */
97
- .dashboard {
98
- display: grid;
99
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
100
- gap: 20px;
101
- margin-bottom: 30px;
100
+ .tabulator-header {
101
+ background-color: #f8fafc !important;
102
+ border-bottom: 2px solid #e2e8f0 !important;
103
+ color: #64748b !important;
104
+ font-weight: 600 !important;
105
+ font-size: 0.75rem !important;
106
+ text-transform: uppercase !important;
107
+ letter-spacing: 0.05em !important;
102
108
  }
103
-
104
- /* Cards */
105
- .card {
106
- background: var(--surface);
107
- padding: 24px;
108
- border-radius: 8px;
109
- box-shadow: var(--shadow);
110
- display: flex;
111
- flex-direction: column;
112
- align-items: center;
113
- justify-content: center;
114
- transition: transform 0.2s;
109
+ .tabulator-header .tabulator-col {
110
+ background-color: #f8fafc !important;
111
+ border-right: none !important;
115
112
  }
116
- .card:hover { transform: translateY(-2px); }
117
-
118
- .number { font-size: 3rem; font-weight: 700; line-height: 1; margin-bottom: 0.5rem; }
119
- .label { color: var(--text-secondary); font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; }
120
-
121
- /* Filters */
122
- .controls {
123
- display: flex;
124
- gap: 15px;
125
- margin-bottom: 20px;
126
- align-items: center;
127
- background: var(--surface);
128
- padding: 15px;
129
- border-radius: 8px;
130
- box-shadow: var(--shadow);
113
+ .tabulator-row {
114
+ background-color: white !important;
115
+ border-bottom: 1px solid #f1f5f9 !important;
116
+ color: #334155 !important;
131
117
  }
132
- .search-box {
133
- flex: 1;
134
- padding: 10px 15px;
135
- border: 1px solid var(--border);
136
- border-radius: 6px;
137
- font-size: 1rem;
118
+ .tabulator-row:hover {
119
+ background-color: #f8fafc !important;
138
120
  }
139
- .filter-group {
140
- display: flex;
141
- gap: 10px;
121
+ .tabulator-row.tabulator-selected {
122
+ background-color: #e0f2fe !important;
142
123
  }
143
- .filter-btn {
144
- padding: 8px 16px;
145
- border: 1px solid var(--border);
146
- background: var(--background);
147
- border-radius: 6px;
148
- cursor: pointer;
149
- font-weight: 500;
150
- color: var(--text-secondary);
151
- display: flex;
152
- align-items: center;
153
- gap: 6px;
124
+ .tabulator-cell {
125
+ padding: 14px 20px !important;
126
+ border-right: none !important;
127
+ font-size: 0.9rem !important;
154
128
  }
155
- .filter-btn.active {
156
- background: var(--primary);
157
- color: white;
158
- border-color: var(--primary);
129
+
130
+ /* Header Filter Inputs */
131
+ .tabulator-header-filter input,
132
+ .tabulator-header-filter select {
133
+ width: 100% !important;
134
+ padding: 6px 10px !important;
135
+ border: 2px solid #cbd5e1 !important;
136
+ border-radius: 6px !important;
137
+ font-size: 0.8rem !important;
138
+ background-color: #ffffff !important;
139
+ color: #334155 !important;
140
+ outline: none !important;
159
141
  }
160
- .filter-btn:hover:not(.active) { background: #e0e0e0; }
161
-
162
- /* Issues Table */
163
- .table-container {
164
- background: var(--surface);
165
- border-radius: 8px;
166
- box-shadow: var(--shadow);
167
- overflow-x: auto;
142
+ .tabulator-header-filter input:focus,
143
+ .tabulator-header-filter select:focus {
144
+ border-color: #0ea5e9 !important;
145
+ box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15) !important;
168
146
  }
169
- table {
170
- width: 100%;
171
- border-collapse: collapse;
147
+ .tabulator-header-filter input::placeholder {
148
+ color: #94a3b8 !important;
172
149
  }
173
150
 
174
- th, td {
175
- text-align: left;
176
- padding: 12px 20px;
177
- border-bottom: 1px solid var(--border);
151
+ /* Tabulator List Filter Styling */
152
+ .tabulator-edit-list {
153
+ background: white !important;
154
+ border: 2px solid #e2e8f0 !important;
155
+ border-radius: 8px !important;
156
+ box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1) !important;
157
+ max-height: 200px !important;
158
+ overflow-y: auto !important;
178
159
  }
179
- th {
180
- background: #f9f9f9;
181
- color: var(--text-secondary);
182
- font-weight: 600;
183
- font-size: 0.85rem;
184
- text-transform: uppercase;
185
- position: sticky;
186
- top: 0;
160
+ .tabulator-edit-list-item {
161
+ padding: 8px 12px !important;
162
+ font-size: 0.85rem !important;
163
+ color: #334155 !important;
187
164
  }
188
- tr:hover { background-color: #f5f9ff; }
189
- tr:last-child td { border-bottom: none; }
190
-
191
- .severity-badge {
192
- font-weight: 700;
193
- text-transform: uppercase;
194
- font-size: 0.75rem;
195
- padding: 4px 8px;
196
- border-radius: 4px;
197
- display: inline-block;
198
- min-width: 60px;
199
- text-align: center;
165
+ .tabulator-edit-list-item:hover {
166
+ background-color: #f1f5f9 !important;
200
167
  }
201
- .bg-error { background-color: #ffebee; color: var(--error); }
202
- .bg-warning { background-color: #fff3e0; color: var(--warning); }
203
- .bg-info { background-color: #e3f2fd; color: var(--info); }
204
-
205
- .file-link { font-family: monospace; font-weight: 600; color: var(--text-primary); }
206
- .location { font-family: monospace; color: var(--text-secondary); }
207
-
208
- .rule-pill {
209
- display: inline-block;
210
- background: #eef2f5;
211
- padding: 2px 8px;
212
- border-radius: 4px;
213
- font-size: 0.8rem;
214
- color: var(--text-secondary);
215
- font-family: monospace;
216
- border: 1px solid #dce1e6;
168
+ .tabulator-edit-list-item.active {
169
+ background-color: #0ea5e9 !important;
170
+ color: white !important;
217
171
  }
218
-
219
- .empty-state {
220
- text-align: center;
221
- padding: 60px;
222
- color: var(--text-secondary);
172
+
173
+ /* Chart Container */
174
+ .chart-container {
175
+ position: relative;
176
+ height: 250px;
177
+ width: 100%;
223
178
  }
224
- .empty-icon { font-size: 3rem; margin-bottom: 1rem; }
225
179
 
226
- /* Responsive */
227
- @media (max-width: 768px) {
228
- .controls { flex-direction: column; align-items: stretch; }
229
- .filter-group { justify-content: space-between; }
230
- }
180
+ [x-cloak] { display: none !important; }
231
181
  </style>
232
182
  </head>
233
183
  <body>
234
- <header>
235
- <div class="container header-content">
236
- <div>
237
- <h1>
238
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg>
239
- ${title}
240
- </h1>
241
- <div class="meta">Generated on ${date}</div>
242
- </div>
243
- <div>
244
- <a href="#" onclick="window.print()" style="color: var(--primary); text-decoration: none; font-weight: 500;">Download / Print</a>
245
- </div>
246
- </div>
247
- </header>
248
184
 
249
- <div class="container">
250
- <!-- Dashboard -->
251
- <div class="dashboard">
252
- <div class="card">
253
- <span class="number" style="color: var(--error)">${totalErrors}</span>
254
- <span class="label">Errors</span>
255
- </div>
256
- <div class="card">
257
- <span class="number" style="color: var(--warning)">${totalWarnings}</span>
258
- <span class="label">Warnings</span>
259
- </div>
260
- <div class="card">
261
- <span class="number" style="color: var(--info)">${totalInfos}</span>
262
- <span class="label">Infos</span>
263
- </div>
264
- <div class="card">
265
- <span class="number">${report.files.length}</span>
266
- <span class="label">Files Scanned</span>
267
- </div>
268
- </div>
185
+ <!-- Data Injection -->
186
+ <script id="report-data" type="application/json">
187
+ ${jsonPayload}
188
+ </script>
189
+
190
+ <div id="app" class="min-h-screen flex flex-col">
191
+
192
+ <!-- Navbar -->
193
+ <header class="bg-white border-b border-gray-200 sticky top-0 z-50">
194
+ <div class="max-w-[1600px] mx-auto px-4 sm:px-6 lg:px-8">
195
+ <div class="flex justify-between h-16">
196
+ <div class="flex items-center gap-4">
197
+ <div class="flex items-center gap-2">
198
+ <div class="bg-brand-600 text-white p-1.5 rounded-lg shadow-sm">
199
+ <i data-lucide="shield-check" class="w-6 h-6"></i>
200
+ </div>
201
+ <div>
202
+ <h1 class="text-xl font-bold text-gray-900 tracking-tight">Mule-Lint</h1>
203
+ <p class="text-xs text-gray-500 font-medium">Enterprise Static Analysis</p>
204
+ </div>
205
+ </div>
206
+
207
+ <!-- Tabs -->
208
+ <nav class="ml-10 flex space-x-1 bg-gray-100 p-1 rounded-lg">
209
+ <button onclick="router.navigate('dashboard')"
210
+ id="nav-dashboard"
211
+ data-active="true"
212
+ class="px-4 py-1.5 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-900 data-[active=true]:bg-white data-[active=true]:text-brand-600 data-[active=true]:shadow-sm">
213
+ Dashboard
214
+ </button>
215
+ <button onclick="router.navigate('issues')"
216
+ id="nav-issues"
217
+ class="px-4 py-1.5 rounded-md text-sm font-medium transition-all duration-200 text-gray-600 hover:text-gray-900 data-[active=true]:bg-white data-[active=true]:text-brand-600 data-[active=true]:shadow-sm">
218
+ Issues
219
+ <span id="nav-badge" class="ml-2 bg-gray-200 text-gray-600 px-1.5 py-0.5 rounded-full text-xs">0</span>
220
+ </button>
221
+ </nav>
222
+ </div>
269
223
 
270
- <!-- Controls -->
271
- <div class="controls">
272
- <input type="text" id="searchInput" class="search-box" placeholder="Search by file, message, or rule..." onkeyup="filterTable()">
273
- <div class="filter-group">
274
- <button class="filter-btn active" onclick="toggleFilter('all', this)" id="btn-all">All</button>
275
- <button class="filter-btn" onclick="toggleFilter('error', this)" id="btn-error">Errors</button>
276
- <button class="filter-btn" onclick="toggleFilter('warning', this)" id="btn-warning">Warnings</button>
277
- <button class="filter-btn" onclick="toggleFilter('info', this)" id="btn-info">Infos</button>
224
+ <div class="flex items-center gap-4">
225
+ <span class="text-sm text-gray-500 hidden md:block">
226
+ Generated <span id="timestamp-display" class="font-mono text-gray-700"></span>
227
+ </span>
228
+ <div class="h-6 w-px bg-gray-200"></div>
229
+ <a href="https://github.com/mulesoft-labs/mule-lint" target="_blank" class="text-gray-500 hover:text-gray-900 transition-colors">
230
+ <i data-lucide="github" class="w-5 h-5"></i>
231
+ </a>
232
+ <button onclick="window.print()" class="text-gray-500 hover:text-brand-600 transition-colors" title="Print Report">
233
+ <i data-lucide="printer" class="w-5 h-5"></i>
234
+ </button>
235
+ </div>
236
+ </div>
278
237
  </div>
279
- </div>
238
+ </header>
280
239
 
281
- <!-- Main Table -->
282
- <div class="table-container">
283
- <table id="issuesTable">
284
- <thead>
285
- <tr>
286
- <th width="100">Severity</th>
287
- <th width="150">Rule</th>
288
- <th width="300">File</th>
289
- <th width="100">Location</th>
290
- <th>Message</th>
291
- </tr>
292
- </thead>
293
- <tbody>
294
- ${allIssues.map(issue => renderIssueRow(issue)).join('')}
295
- </tbody>
296
- </table>
240
+ <!-- Main Content -->
241
+ <main class="flex-1 w-full">
297
242
 
298
- ${totalIssues === 0 && report.summary.parseErrors === 0 ? `
299
- <div class="empty-state">
300
- <div class="empty-icon">🎉</div>
301
- <h2>No issues found!</h2>
302
- <p>Your MuleSoft code looks clean and compliant.</p>
243
+ <!-- Dashboard View -->
244
+ <div id="view-dashboard" class="space-y-6 max-w-[1600px] mx-auto px-4 sm:px-6 lg:px-8 py-8">
245
+ <!-- Summary Cards -->
246
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
247
+ <!-- Error Card -->
248
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex items-start justify-between cursor-pointer hover:shadow-md transition-shadow group" onclick="router.filterBySeverity('error')">
249
+ <div>
250
+ <p class="text-sm font-medium text-gray-500">Errors</p>
251
+ <h3 class="text-3xl font-bold text-severity-error mt-2" id="stat-error">0</h3>
252
+ <p class="text-xs text-gray-400 mt-1 group-hover:text-red-400 transition-colors">Critical violations</p>
253
+ </div>
254
+ <div class="p-3 bg-red-50 rounded-lg group-hover:bg-red-100 transition-colors">
255
+ <i data-lucide="x-circle" class="w-6 h-6 text-severity-error"></i>
256
+ </div>
257
+ </div>
258
+
259
+ <!-- Warning Card -->
260
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex items-start justify-between cursor-pointer hover:shadow-md transition-shadow group" onclick="router.filterBySeverity('warning')">
261
+ <div>
262
+ <p class="text-sm font-medium text-gray-500">Warnings</p>
263
+ <h3 class="text-3xl font-bold text-severity-warning mt-2" id="stat-warning">0</h3>
264
+ <p class="text-xs text-gray-400 mt-1 group-hover:text-orange-400 transition-colors">Potential issues</p>
265
+ </div>
266
+ <div class="p-3 bg-orange-50 rounded-lg group-hover:bg-orange-100 transition-colors">
267
+ <i data-lucide="alert-triangle" class="w-6 h-6 text-severity-warning"></i>
268
+ </div>
269
+ </div>
270
+
271
+ <!-- Info Card -->
272
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex items-start justify-between cursor-pointer hover:shadow-md transition-shadow group" onclick="router.filterBySeverity('info')">
273
+ <div>
274
+ <p class="text-sm font-medium text-gray-500">Infos</p>
275
+ <h3 class="text-3xl font-bold text-severity-info mt-2" id="stat-info">0</h3>
276
+ <p class="text-xs text-gray-400 mt-1 group-hover:text-blue-400 transition-colors">Suggestions</p>
277
+ </div>
278
+ <div class="p-3 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
279
+ <i data-lucide="info" class="w-6 h-6 text-severity-info"></i>
280
+ </div>
281
+ </div>
282
+
283
+ <!-- Files Card -->
284
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex items-start justify-between">
285
+ <div>
286
+ <p class="text-sm font-medium text-gray-500">Files Scanned</p>
287
+ <h3 class="text-3xl font-bold text-gray-700 mt-2" id="stat-files">0</h3>
288
+ <p class="text-xs text-gray-400 mt-1">XML Resources</p>
289
+ </div>
290
+ <div class="p-3 bg-gray-50 rounded-lg">
291
+ <i data-lucide="file-code" class="w-6 h-6 text-gray-500"></i>
292
+ </div>
293
+ </div>
294
+ </div>
295
+
296
+ <!-- Charts Section -->
297
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
298
+ <!-- Top Rules -->
299
+ <div class="lg:col-span-2 bg-white rounded-xl shadow-sm border border-gray-100 p-6">
300
+ <div class="flex items-center justify-between mb-6">
301
+ <h3 class="text-lg font-semibold text-gray-800">Top 5 Violated Rules</h3>
302
+ </div>
303
+ <div class="chart-container">
304
+ <canvas id="chart-top-rules"></canvas>
305
+ </div>
306
+ </div>
307
+
308
+ <!-- Severity Distribution -->
309
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
310
+ <div class="flex items-center justify-between mb-6">
311
+ <h3 class="text-lg font-semibold text-gray-800">Severity Breakdown</h3>
312
+ </div>
313
+ <div class="chart-container flex items-center justify-center">
314
+ <canvas id="chart-severity"></canvas>
315
+ </div>
316
+ </div>
317
+ </div>
318
+
319
+ <!-- Categories Section -->
320
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
321
+ <div class="flex items-center justify-between mb-6">
322
+ <h3 class="text-lg font-semibold text-gray-800">Issues by Category</h3>
323
+ <button onclick="router.navigate('issues')" class="text-sm text-brand-600 hover:text-brand-900 font-medium">View All Issues &rarr;</button>
324
+ </div>
325
+ <div class="h-[300px] w-full relative">
326
+ <canvas id="chart-categories"></canvas>
327
+ </div>
328
+ </div>
303
329
  </div>
304
- ` : ''}
305
-
306
- <div id="noResults" class="empty-state" style="display: none;">
307
- <h2>No matching issues found</h2>
308
- <p>Try adjusting your search filters.</p>
330
+
331
+ <!-- Issues View -->
332
+ <div id="view-issues" class="hidden h-[calc(100vh-80px)] flex flex-col px-6 py-4 overflow-hidden">
333
+ <!-- Filters Toolbar -->
334
+ <div class="bg-white p-4 rounded-t-xl border border-gray-200 border-b-0 shadow-sm flex flex-wrap gap-4 items-center justify-between flex-shrink-0">
335
+ <div class="flex items-center gap-4 flex-1">
336
+ <div class="relative flex-1 max-w-md">
337
+ <i data-lucide="search" class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"></i>
338
+ <input type="text" id="global-search" placeholder="Quick search..."
339
+ class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent transition-shadow">
340
+ </div>
341
+ <div class="text-sm text-gray-500 italic">
342
+ <i data-lucide="filter" class="w-4 h-4 inline mr-1"></i>
343
+ Use column headers to filter (multiselect supported)
344
+ </div>
345
+ </div>
346
+
347
+ <div class="flex items-center gap-2">
348
+ <button id="download-csv" class="flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-600 bg-gray-50 border border-gray-300 rounded-lg hover:bg-gray-100 transition-colors">
349
+ <i data-lucide="download" class="w-4 h-4"></i>
350
+ Export CSV
351
+ </button>
352
+ </div>
353
+ </div>
354
+
355
+ <!-- Tabulator Container - uses remaining height -->
356
+ <div id="issues-table-container" class="flex-1 bg-white border border-gray-200 rounded-b-xl overflow-hidden shadow-sm"></div>
309
357
  </div>
310
- </div>
358
+ </main>
311
359
  </div>
312
360
 
313
361
  <script>
314
- let currentSeverity = 'all';
362
+ // --- State ---
363
+ const reportRaw = document.getElementById('report-data').textContent;
364
+ const report = JSON.parse(reportRaw);
365
+
366
+ // Flatten issues for the table
367
+ const allIssues = report.files.flatMap(f => f.issues.map(i => ({
368
+ ...i,
369
+ fileName: f.relativePath
370
+ })));
315
371
 
316
- function toggleFilter(severity, btn) {
317
- currentSeverity = severity;
318
-
319
- // Update buttons
320
- document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
321
- btn.classList.add('active');
372
+ // --- Router ---
373
+ const router = {
374
+ navigate(view) {
375
+ ['dashboard', 'issues'].forEach(v => {
376
+ document.getElementById(\`view-\${v}\`).classList.toggle('hidden', v !== view);
377
+ const btn = document.getElementById(\`nav-\${v}\`);
378
+ if (v === view) btn.setAttribute('data-active', 'true');
379
+ else btn.removeAttribute('data-active');
380
+ });
381
+ if (view === 'issues' && window.tableInstance) window.tableInstance.redraw();
382
+ },
322
383
 
323
- filterTable();
324
- }
384
+ filterBySeverity(severity) {
385
+ this.navigate('issues');
386
+ window.tableInstance.setHeaderFilterValue("severity", [severity]);
387
+ }
388
+ };
325
389
 
326
- function filterTable() {
327
- const input = document.getElementById('searchInput');
328
- const filter = input.value.toLowerCase();
329
- const table = document.getElementById('issuesTable');
330
- const tr = table.getElementsByTagName('tr');
331
- let visibleCount = 0;
390
+ // --- Renderer ---
391
+ const renderer = {
392
+ init() {
393
+ document.getElementById('timestamp-display').textContent = new Date(report.metadata.timestamp).toLocaleString();
394
+
395
+ document.getElementById('stat-error').textContent = report.summary.bySeverity.error;
396
+ document.getElementById('stat-warning').textContent = report.summary.bySeverity.warning;
397
+ document.getElementById('stat-info').textContent = report.summary.bySeverity.info;
398
+ document.getElementById('stat-files').textContent = report.metadata.filesScanned;
399
+ document.getElementById('nav-badge').textContent = allIssues.length;
400
+
401
+ this.renderCharts();
402
+ this.initTable();
403
+ lucide.createIcons();
404
+ },
332
405
 
333
- for (let i = 1; i < tr.length; i++) {
334
- const row = tr[i];
335
- const severity = row.getAttribute('data-severity');
336
- const text = row.innerText.toLowerCase();
406
+ renderCharts() {
407
+ const colors = { error: '#ef4444', warning: '#f59e0b', info: '#3b82f6' };
408
+
409
+ // Top Rules (Bar) - Using Names
410
+ const ruleCounts = {};
411
+ const ruleNames = {};
412
+ allIssues.forEach(i => {
413
+ ruleCounts[i.ruleId] = (ruleCounts[i.ruleId] || 0) + 1;
414
+ ruleNames[i.ruleId] = i.ruleName;
415
+ });
416
+
417
+ const sortedRules = Object.entries(ruleCounts)
418
+ .sort((a, b) => b[1] - a[1])
419
+ .slice(0, 5);
337
420
 
338
- const severityMatch = currentSeverity === 'all' || severity === currentSeverity;
339
- const textMatch = text.includes(filter);
421
+ new Chart(document.getElementById('chart-top-rules'), {
422
+ type: 'bar',
423
+ data: {
424
+ labels: sortedRules.map(x => {
425
+ const id = x[0];
426
+ const name = ruleNames[id];
427
+ return name.length > 30 ? name.substring(0, 27) + '...' : name;
428
+ }),
429
+ datasets: [{
430
+ label: 'Violations',
431
+ data: sortedRules.map(x => x[1]),
432
+ backgroundColor: '#0ea5e9',
433
+ borderRadius: 6,
434
+ }]
435
+ },
436
+ options: {
437
+ maintainAspectRatio: false,
438
+ plugins: {
439
+ legend: { display: false },
440
+ tooltip: {
441
+ callbacks: {
442
+ title: (ctx) => {
443
+ const idx = ctx[0].dataIndex;
444
+ const id = sortedRules[idx][0];
445
+ return \`\${ruleNames[id]} (\${id})\`;
446
+ }
447
+ }
448
+ }
449
+ },
450
+ scales: { y: { beginAtZero: true, grid: { borderDash: [2, 4], color: '#f1f5f9' } }, x: { grid: { display: false } } }
451
+ }
452
+ });
340
453
 
341
- if (severityMatch && textMatch) {
342
- row.style.display = '';
343
- visibleCount++;
344
- } else {
345
- row.style.display = 'none';
346
- }
347
- }
348
-
349
- // Show/hide no results message
350
- const noResults = document.getElementById('noResults');
351
- const emptyState = document.querySelector('.empty-state:not(#noResults)');
352
-
353
- if (emptyState) return; // Don't interfere if main empty state is shown
354
-
355
- if (visibleCount === 0 && tr.length > 1) {
356
- noResults.style.display = 'block';
357
- table.style.display = 'none';
358
- } else {
359
- noResults.style.display = 'none';
360
- table.style.display = '';
454
+ // Severity (Doughnut)
455
+ new Chart(document.getElementById('chart-severity'), {
456
+ type: 'doughnut',
457
+ data: {
458
+ labels: ['Error', 'Warning', 'Info'],
459
+ datasets: [{
460
+ data: [report.summary.bySeverity.error, report.summary.bySeverity.warning, report.summary.bySeverity.info],
461
+ backgroundColor: [colors.error, colors.warning, colors.info],
462
+ borderWidth: 0,
463
+ hoverOffset: 4
464
+ }]
465
+ },
466
+ options: {
467
+ cutout: '75%',
468
+ plugins: { legend: { position: 'bottom', labels: { usePointStyle: true, padding: 20 } } }
469
+ }
470
+ });
471
+
472
+ // Categories (Bar)
473
+ const catCounts = {};
474
+ allIssues.forEach(i => catCounts[i.category] = (catCounts[i.category] || 0) + 1);
475
+ const sortedCats = Object.entries(catCounts).sort((a,b) => b[1] - a[1]);
476
+
477
+ new Chart(document.getElementById('chart-categories'), {
478
+ type: 'bar',
479
+ data: {
480
+ labels: sortedCats.map(x => x[0].charAt(0).toUpperCase() + x[0].slice(1)),
481
+ datasets: [{
482
+ label: 'Issues',
483
+ data: sortedCats.map(x => x[1]),
484
+ backgroundColor: '#64748b',
485
+ borderRadius: 4,
486
+ barThickness: 20
487
+ }]
488
+ },
489
+ options: {
490
+ indexAxis: 'y',
491
+ maintainAspectRatio: false,
492
+ plugins: { legend: { display: false } },
493
+ scales: { x: { beginAtZero: true, grid: { borderDash: [2, 4], color: '#f1f5f9' } }, y: { grid: { display: false } } }
494
+ }
495
+ });
496
+ },
497
+
498
+ initTable() {
499
+ const table = new Tabulator("#issues-table-container", {
500
+ data: allIssues,
501
+ layout: "fitColumns",
502
+ height: "100%",
503
+ placeholder: "No issues found matching filters",
504
+ frozenRows: 0, // Header is always frozen in Tabulator by default
505
+
506
+ columns: [
507
+ {
508
+ title: "Severity",
509
+ field: "severity",
510
+ width: 140,
511
+ headerFilter: "list",
512
+ headerFilterParams: {
513
+ valuesLookup: true,
514
+ multiselect: true,
515
+ clearable: true
516
+ },
517
+ headerFilterFunc: "in",
518
+ formatter: (cell) => {
519
+ const val = cell.getValue();
520
+ const colorMap = {
521
+ error: "bg-red-100 text-red-700 border-red-200",
522
+ warning: "bg-orange-100 text-orange-700 border-orange-200",
523
+ info: "bg-blue-100 text-blue-700 border-blue-200"
524
+ };
525
+ return '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border ' + (colorMap[val] || 'bg-gray-100') + ' uppercase tracking-wide">' + val + '</span>';
526
+ }
527
+ },
528
+ {
529
+ title: "Rule",
530
+ field: "ruleName",
531
+ width: 250,
532
+ headerFilter: "list",
533
+ headerFilterParams: {
534
+ valuesLookup: true,
535
+ multiselect: true,
536
+ clearable: true
537
+ },
538
+ headerFilterFunc: "in",
539
+ formatter: (cell) => {
540
+ const row = cell.getRow().getData();
541
+ return '<div class="flex flex-col"><span class="font-medium text-sm text-gray-900">' + cell.getValue() + '</span><span class="text-xs text-gray-500 font-mono">' + row.ruleId + '</span></div>';
542
+ }
543
+ },
544
+ {
545
+ title: "Category",
546
+ field: "category",
547
+ width: 140,
548
+ headerFilter: "list",
549
+ headerFilterParams: {
550
+ valuesLookup: true,
551
+ multiselect: true,
552
+ clearable: true
553
+ },
554
+ headerFilterFunc: "in",
555
+ formatter: (cell) => '<span class="text-sm text-gray-600 capitalize">' + cell.getValue() + '</span>'
556
+ },
557
+ {
558
+ title: "File Path",
559
+ field: "fileName",
560
+ headerFilter: "input",
561
+ headerFilterPlaceholder: "Filter...",
562
+ formatter: (cell) => {
563
+ const row = cell.getRow().getData();
564
+ return '<div class="flex flex-col"><span class="font-mono text-sm text-brand-600 font-medium truncate" title="' + row.fileName + '">' + row.fileName + '</span><span class="text-xs text-gray-400 font-mono">Line: ' + row.line + '</span></div>';
565
+ },
566
+ },
567
+ {
568
+ title: "Message",
569
+ field: "message",
570
+ widthGrow: 2,
571
+ headerFilter: "input",
572
+ headerFilterPlaceholder: "Filter...",
573
+ formatter: (cell) => {
574
+ const row = cell.getRow().getData();
575
+ return '<div class="flex flex-col gap-1"><span class="text-sm text-gray-700">' + cell.getValue() + '</span><span class="text-xs text-gray-400">' + row.ruleDescription + '</span></div>';
576
+ }
577
+ }
578
+ ],
579
+ initialSort: [{ column: "severity", dir: "asc" }]
580
+ });
581
+
582
+ window.tableInstance = table;
583
+
584
+ // Quick Search
585
+ document.getElementById('global-search').addEventListener('keyup', (e) => {
586
+ const term = e.target.value.toLowerCase();
587
+ if (!term) { table.clearFilter(); return; }
588
+ table.setFilter((data) => (
589
+ data.message.toLowerCase().includes(term) ||
590
+ data.fileName.toLowerCase().includes(term) ||
591
+ data.ruleName.toLowerCase().includes(term) ||
592
+ data.ruleId.toLowerCase().includes(term)
593
+ ));
594
+ });
595
+
596
+ // Export
597
+ document.getElementById('download-csv').addEventListener('click', () => {
598
+ table.download("csv", "mule-lint-report.csv");
599
+ });
361
600
  }
362
- }
601
+ };
602
+
603
+ // --- Init ---
604
+ document.addEventListener('DOMContentLoaded', () => {
605
+ renderer.init();
606
+ });
607
+
363
608
  </script>
364
609
  </body>
365
610
  </html>`;
366
611
  }
367
- function renderIssueRow(issue) {
368
- const badgeClass = issue.severity === 'error' ? 'bg-error' :
369
- issue.severity === 'warning' ? 'bg-warning' : 'bg-info';
370
- return `<tr data-severity="${issue.severity}">
371
- <td><span class="severity-badge ${badgeClass}">${issue.severity}</span></td>
372
- <td><span class="rule-pill">${issue.ruleId}</span></td>
373
- <td class="file-link" title="${issue.file}">${issue.file}</td>
374
- <td class="location">${issue.line}:${issue.column}</td>
375
- <td>${escapeHtml(issue.message)}</td>
376
- </tr>`;
377
- }
378
- function escapeHtml(unsafe) {
379
- return unsafe
380
- .replace(/&/g, "&amp;")
381
- .replace(/</g, "&lt;")
382
- .replace(/>/g, "&gt;")
383
- .replace(/"/g, "&quot;")
384
- .replace(/'/g, "&#039;");
385
- }
386
612
  //# sourceMappingURL=HtmlFormatter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HtmlFormatter.js","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HtmlFormatter.js","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":";;AAMA,gCA8lBC;AAnmBD,oCAAqC;AAErC;;GAEG;AACH,SAAgB,UAAU,CAAC,MAAkB;IACzC,iBAAiB;IACjB,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5C,GAAG,IAAI;QACP,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YAC5B,MAAM,OAAO,GAAG,iBAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;YAC3D,OAAO;gBACH,GAAG,KAAK;gBACR,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,SAAS;gBACxC,eAAe,EAAE,OAAO,EAAE,WAAW,IAAI,0BAA0B;gBACnE,QAAQ,EAAE,OAAO,EAAE,IAAI,IAAI,KAAK,CAAC,MAAM;gBACvC,IAAI,EAAE,IAAI,CAAC,YAAY;aAC1B,CAAC;QACN,CAAC,CAAC;KACL,CAAC,CAAC,CAAC;IAEJ,yCAAyC;IACzC,MAAM,UAAU,GAAG;QACf,QAAQ,EAAE;YACN,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,OAAO,EAAE,OAAO;YAChB,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;YACjC,QAAQ,EAAE,CAAC;SACd;QACD,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,aAAa;QACpB,KAAK,EAAE,iBAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;KACtG,CAAC;IAEF,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAExE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAuJD,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAuab,CAAC;AACT,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sfdxy/mule-lint",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "Static analysis tool for MuleSoft applications - supports humans, AI agents, and CI/CD pipelines",
5
5
  "author": "Avinava",
6
6
  "license": "MIT",