@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 (
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
|
6
|
+
* Format lint report as a modern, interactive HTML Single Page Application
|
|
6
7
|
*/
|
|
7
8
|
function formatHtml(report) {
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
/*
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
105
|
-
|
|
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
|
-
.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
.
|
|
133
|
-
|
|
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
|
-
.
|
|
140
|
-
|
|
141
|
-
gap: 10px;
|
|
121
|
+
.tabulator-row.tabulator-selected {
|
|
122
|
+
background-color: #e0f2fe !important;
|
|
142
123
|
}
|
|
143
|
-
.
|
|
144
|
-
padding:
|
|
145
|
-
border:
|
|
146
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
border-collapse: collapse;
|
|
147
|
+
.tabulator-header-filter input::placeholder {
|
|
148
|
+
color: #94a3b8 !important;
|
|
172
149
|
}
|
|
173
150
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
189
|
-
|
|
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
|
-
.
|
|
202
|
-
|
|
203
|
-
|
|
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
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
</
|
|
238
|
+
</header>
|
|
280
239
|
|
|
281
|
-
<!-- Main
|
|
282
|
-
<
|
|
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
|
-
|
|
299
|
-
<div class="
|
|
300
|
-
|
|
301
|
-
<
|
|
302
|
-
|
|
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 →</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="
|
|
307
|
-
|
|
308
|
-
<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
|
-
</
|
|
358
|
+
</main>
|
|
311
359
|
</div>
|
|
312
360
|
|
|
313
361
|
<script>
|
|
314
|
-
|
|
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
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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
|
-
|
|
324
|
-
|
|
384
|
+
filterBySeverity(severity) {
|
|
385
|
+
this.navigate('issues');
|
|
386
|
+
window.tableInstance.setHeaderFilterValue("severity", [severity]);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
325
389
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
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
|
-
|
|
339
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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, "&")
|
|
381
|
-
.replace(/</g, "<")
|
|
382
|
-
.replace(/>/g, ">")
|
|
383
|
-
.replace(/"/g, """)
|
|
384
|
-
.replace(/'/g, "'");
|
|
385
|
-
}
|
|
386
612
|
//# sourceMappingURL=HtmlFormatter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HtmlFormatter.js","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":";;AAMA,
|
|
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"}
|