@wtdlee/repomap 0.9.0 → 0.10.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 +12 -0
- package/dist/analyzers/index.d.ts +8 -8
- package/dist/analyzers/index.js +1 -1
- package/dist/{chunk-SMN6XFMS.js → chunk-ATRSGO6O.js} +270 -196
- package/dist/chunk-IGRCLYVZ.js +451 -0
- package/dist/{chunk-P7MX3M5U.js → chunk-LHP2OKKA.js} +428 -76
- package/dist/chunk-QBSB6BIU.js +20 -0
- package/dist/{chunk-LDX6WPHR.js → chunk-YKPXOHWZ.js} +196 -37
- package/dist/chunk-ZWRDP37E.js +1 -0
- package/dist/cli.js +14 -14
- package/dist/{dataflow-analyzer-CJ2T0cGS.d.ts → dataflow-analyzer-DIUsRpvv.d.ts} +18 -0
- package/dist/{env-detector-BIWJ7OYF.js → env-detector-RVGPBVNJ.js} +1 -1
- package/dist/generators/assets/docs.css +176 -1
- package/dist/generators/assets/page-map.css +59 -0
- package/dist/generators/assets/rails-map.css +13 -0
- package/dist/generators/index.d.ts +2 -1
- package/dist/generators/index.js +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +1 -1
- package/dist/page-map-generator-LTVRHSDC.js +1 -0
- package/dist/{rails-3HNUFTQV.js → rails-57MNOGHR.js} +1 -1
- package/dist/rails-map-generator-JNU5QHX4.js +1 -0
- package/dist/server/index.js +1 -1
- package/dist/types.d.ts +34 -1
- package/package.json +1 -1
- package/dist/chunk-HPBPEGHS.js +0 -19
- package/dist/chunk-TNUKDIO7.js +0 -5
- package/dist/page-map-generator-2XQB7RWO.js +0 -1
- package/dist/rails-map-generator-77ATUFMP.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {k}from'./chunk-H7VVRHQZ.js';import*as
|
|
2
|
-
\u{1F4C4} Generated: ${t.outputPath}`)),s}generateFromResult(t,e="Rails Application Map"){return this.result=t,this.generateHTML(e)}generateHTML(t){if(!this.result)throw new Error("Analysis not run");let{routes:e,controllers:s,models:a,grpc:l,summary:
|
|
1
|
+
import {k}from'./chunk-H7VVRHQZ.js';import*as c from'fs';import*as d from'path';var i=class{constructor(t){this.rootPath=t;}result=null;async generate(t={}){if(!this.rootPath)throw new Error("Root path required for analysis");let{title:e="Rails Application Map"}=t;this.result=await k(this.rootPath);let s=this.generateHTML(e);return t.outputPath&&(c.writeFileSync(t.outputPath,s),console.log(`
|
|
2
|
+
\u{1F4C4} Generated: ${t.outputPath}`)),s}generateFromResult(t,e="Rails Application Map"){return this.result=t,this.generateHTML(e)}generateHTML(t){if(!this.result)throw new Error("Analysis not run");let{routes:e,controllers:s,models:a,grpc:l,summary:n}=this.result;return `<!DOCTYPE html>
|
|
3
3
|
<html lang="en">
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8">
|
|
@@ -23,25 +23,25 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
23
23
|
<div class="stats-bar">
|
|
24
24
|
<div class="stat active" data-view="routes">
|
|
25
25
|
<div>
|
|
26
|
-
<div class="stat-value">${
|
|
26
|
+
<div class="stat-value">${n.totalRoutes.toLocaleString()}</div>
|
|
27
27
|
<div class="stat-label">Routes</div>
|
|
28
28
|
</div>
|
|
29
29
|
</div>
|
|
30
30
|
<div class="stat" data-view="controllers">
|
|
31
31
|
<div>
|
|
32
|
-
<div class="stat-value">${
|
|
32
|
+
<div class="stat-value">${n.totalControllers}</div>
|
|
33
33
|
<div class="stat-label">Controllers</div>
|
|
34
34
|
</div>
|
|
35
35
|
</div>
|
|
36
36
|
<div class="stat" data-view="models">
|
|
37
37
|
<div>
|
|
38
|
-
<div class="stat-value">${
|
|
38
|
+
<div class="stat-value">${n.totalModels}</div>
|
|
39
39
|
<div class="stat-label">Models</div>
|
|
40
40
|
</div>
|
|
41
41
|
</div>
|
|
42
42
|
<div class="stat" data-view="grpc">
|
|
43
43
|
<div>
|
|
44
|
-
<div class="stat-value">${
|
|
44
|
+
<div class="stat-value">${n.totalGrpcServices}</div>
|
|
45
45
|
<div class="stat-label">gRPC</div>
|
|
46
46
|
</div>
|
|
47
47
|
</div>
|
|
@@ -62,7 +62,7 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
62
62
|
</div>
|
|
63
63
|
|
|
64
64
|
<div class="sidebar-section namespaces" id="namespaceFilter">
|
|
65
|
-
<div class="sidebar-title">Namespaces (${
|
|
65
|
+
<div class="sidebar-title">Namespaces (${n.namespaces.length})</div>
|
|
66
66
|
<div class="namespace-list">
|
|
67
67
|
<div class="namespace-item active" data-namespace="all">
|
|
68
68
|
<span>All</span>
|
|
@@ -103,6 +103,11 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
103
103
|
let currentView = 'routes';
|
|
104
104
|
let selectedNamespaces = new Set(['all']);
|
|
105
105
|
let selectedMethods = new Set(['all']);
|
|
106
|
+
let selectedControllerFlags = new Set(['all']);
|
|
107
|
+
let selectedModelNamespaces = new Set(['all']);
|
|
108
|
+
let selectedModelFlags = new Set(['all']);
|
|
109
|
+
let selectedGrpcNamespaces = new Set(['all']);
|
|
110
|
+
let selectedGrpcFlags = new Set(['all']);
|
|
106
111
|
let searchQuery = '';
|
|
107
112
|
let routesDisplayCount = 200;
|
|
108
113
|
let controllersDisplayCount = 50;
|
|
@@ -177,68 +182,83 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
177
182
|
});
|
|
178
183
|
});
|
|
179
184
|
|
|
180
|
-
//
|
|
181
|
-
document.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
185
|
+
// Sidebar filter click handler (works even after sidebar re-render)
|
|
186
|
+
document.addEventListener('click', (e) => {
|
|
187
|
+
const target = e.target instanceof Element ? e.target : e.target?.parentElement;
|
|
188
|
+
if (!target) return;
|
|
189
|
+
const item = target.closest('.namespace-item');
|
|
190
|
+
if (!item) return;
|
|
191
|
+
|
|
192
|
+
const filterType = item.dataset.filterType;
|
|
193
|
+
const value = item.dataset.filterValue;
|
|
194
|
+
if (!filterType || value === undefined) return;
|
|
195
|
+
|
|
196
|
+
const multi = e.ctrlKey || e.metaKey;
|
|
197
|
+
|
|
198
|
+
function toggleMulti(setRef, v) {
|
|
199
|
+
if (v === 'all') return new Set(['all']);
|
|
200
|
+
const next = new Set(setRef);
|
|
201
|
+
next.delete('all');
|
|
202
|
+
if (next.has(v)) next.delete(v);
|
|
203
|
+
else next.add(v);
|
|
204
|
+
if (next.size === 0) next.add('all');
|
|
205
|
+
return next;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function toggleSingle(v) {
|
|
209
|
+
return new Set([v]);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (filterType === 'routeNamespace') {
|
|
213
|
+
selectedNamespaces = multi ? toggleMulti(selectedNamespaces, value) : toggleSingle(value);
|
|
202
214
|
routesDisplayCount = 200;
|
|
203
215
|
saveStateToUrl();
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// Method filter (multi-select with Ctrl/Cmd)
|
|
209
|
-
document.querySelectorAll('.namespace-item[data-method]').forEach(item => {
|
|
210
|
-
item.addEventListener('click', (e) => {
|
|
211
|
-
const method = item.dataset.method;
|
|
212
|
-
if (e.ctrlKey || e.metaKey) {
|
|
213
|
-
if (selectedMethods.has('all')) {
|
|
214
|
-
selectedMethods = new Set([method]);
|
|
215
|
-
} else if (selectedMethods.has(method)) {
|
|
216
|
-
selectedMethods.delete(method);
|
|
217
|
-
if (selectedMethods.size === 0) selectedMethods.add('all');
|
|
218
|
-
} else {
|
|
219
|
-
selectedMethods.add(method);
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
if (selectedMethods.has(method) && selectedMethods.size === 1) {
|
|
223
|
-
selectedMethods = new Set(['all']);
|
|
224
|
-
} else {
|
|
225
|
-
selectedMethods = new Set([method]);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
updateFilterUI();
|
|
216
|
+
} else if (filterType === 'routeMethod') {
|
|
217
|
+
// Methods behave similarly to namespaces
|
|
218
|
+
selectedMethods = multi ? toggleMulti(selectedMethods, value) : toggleSingle(value);
|
|
229
219
|
routesDisplayCount = 200;
|
|
230
220
|
saveStateToUrl();
|
|
231
|
-
|
|
232
|
-
|
|
221
|
+
} else if (filterType === 'controllerFlag') {
|
|
222
|
+
selectedControllerFlags = multi
|
|
223
|
+
? toggleMulti(selectedControllerFlags, value)
|
|
224
|
+
: toggleSingle(value);
|
|
225
|
+
controllersDisplayCount = 50;
|
|
226
|
+
} else if (filterType === 'modelNamespace') {
|
|
227
|
+
selectedModelNamespaces = multi
|
|
228
|
+
? toggleMulti(selectedModelNamespaces, value)
|
|
229
|
+
: toggleSingle(value);
|
|
230
|
+
modelsDisplayCount = 50;
|
|
231
|
+
} else if (filterType === 'modelFlag') {
|
|
232
|
+
selectedModelFlags = multi ? toggleMulti(selectedModelFlags, value) : toggleSingle(value);
|
|
233
|
+
modelsDisplayCount = 50;
|
|
234
|
+
} else if (filterType === 'grpcNamespace') {
|
|
235
|
+
selectedGrpcNamespaces = multi ? toggleMulti(selectedGrpcNamespaces, value) : toggleSingle(value);
|
|
236
|
+
grpcDisplayCount = 50;
|
|
237
|
+
} else if (filterType === 'grpcFlag') {
|
|
238
|
+
selectedGrpcFlags = multi ? toggleMulti(selectedGrpcFlags, value) : toggleSingle(value);
|
|
239
|
+
grpcDisplayCount = 50;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
updateFilterUI();
|
|
243
|
+
renderMainPanel();
|
|
233
244
|
});
|
|
234
245
|
|
|
235
246
|
function updateFilterUI() {
|
|
236
|
-
document.querySelectorAll('.namespace-item[data-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
247
|
+
document.querySelectorAll('.namespace-item[data-filter-type][data-filter-value]').forEach(item => {
|
|
248
|
+
const t = item.dataset.filterType;
|
|
249
|
+
const v = item.dataset.filterValue;
|
|
250
|
+
if (!t || v === undefined) return;
|
|
251
|
+
|
|
252
|
+
let active = false;
|
|
253
|
+
if (t === 'routeNamespace') active = selectedNamespaces.has(v);
|
|
254
|
+
else if (t === 'routeMethod') active = selectedMethods.has(v);
|
|
255
|
+
else if (t === 'controllerFlag') active = selectedControllerFlags.has(v);
|
|
256
|
+
else if (t === 'modelNamespace') active = selectedModelNamespaces.has(v);
|
|
257
|
+
else if (t === 'modelFlag') active = selectedModelFlags.has(v);
|
|
258
|
+
else if (t === 'grpcNamespace') active = selectedGrpcNamespaces.has(v);
|
|
259
|
+
else if (t === 'grpcFlag') active = selectedGrpcFlags.has(v);
|
|
260
|
+
|
|
261
|
+
item.classList.toggle('active', active);
|
|
242
262
|
});
|
|
243
263
|
}
|
|
244
264
|
|
|
@@ -250,19 +270,10 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
250
270
|
|
|
251
271
|
// Render Functions
|
|
252
272
|
function renderMainPanel() {
|
|
253
|
-
//
|
|
273
|
+
// Update sidebar filters per view (routes/controllers vs models vs grpc)
|
|
254
274
|
const namespaceFilter = document.getElementById('namespaceFilter');
|
|
255
275
|
const methodFilter = document.getElementById('methodFilter');
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if (namespaceFilter) {
|
|
259
|
-
namespaceFilter.style.opacity = filtersDisabled ? '0.4' : '1';
|
|
260
|
-
namespaceFilter.style.pointerEvents = filtersDisabled ? 'none' : 'auto';
|
|
261
|
-
}
|
|
262
|
-
if (methodFilter) {
|
|
263
|
-
methodFilter.style.opacity = filtersDisabled ? '0.4' : '1';
|
|
264
|
-
methodFilter.style.pointerEvents = filtersDisabled ? 'none' : 'auto';
|
|
265
|
-
}
|
|
276
|
+
renderSidebarFilters(namespaceFilter, methodFilter);
|
|
266
277
|
|
|
267
278
|
switch (currentView) {
|
|
268
279
|
case 'routes':
|
|
@@ -285,6 +296,289 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
285
296
|
attachEventListeners();
|
|
286
297
|
}
|
|
287
298
|
|
|
299
|
+
function renderSidebarFilters(namespaceFilter, methodFilter) {
|
|
300
|
+
if (!namespaceFilter || !methodFilter) return;
|
|
301
|
+
|
|
302
|
+
function sectionHtml(title, listClass, inner) {
|
|
303
|
+
return (
|
|
304
|
+
'<div class="sidebar-title">' +
|
|
305
|
+
title +
|
|
306
|
+
'</div>' +
|
|
307
|
+
'<div class="' +
|
|
308
|
+
listClass +
|
|
309
|
+
'">' +
|
|
310
|
+
inner +
|
|
311
|
+
'</div>'
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (currentView === 'routes') {
|
|
316
|
+
namespaceFilter.style.opacity = '1';
|
|
317
|
+
namespaceFilter.style.pointerEvents = 'auto';
|
|
318
|
+
methodFilter.style.opacity = '1';
|
|
319
|
+
methodFilter.style.pointerEvents = 'auto';
|
|
320
|
+
|
|
321
|
+
namespaceFilter.innerHTML = sectionHtml(
|
|
322
|
+
'Namespaces',
|
|
323
|
+
'namespace-list',
|
|
324
|
+
renderRouteNamespaceFilters()
|
|
325
|
+
);
|
|
326
|
+
methodFilter.innerHTML = sectionHtml(
|
|
327
|
+
'HTTP Methods',
|
|
328
|
+
'namespace-list methods-list',
|
|
329
|
+
renderRouteMethodFilters()
|
|
330
|
+
);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (currentView === 'controllers') {
|
|
335
|
+
namespaceFilter.style.opacity = '1';
|
|
336
|
+
namespaceFilter.style.pointerEvents = 'auto';
|
|
337
|
+
methodFilter.style.opacity = '1';
|
|
338
|
+
methodFilter.style.pointerEvents = 'auto';
|
|
339
|
+
|
|
340
|
+
namespaceFilter.innerHTML = sectionHtml(
|
|
341
|
+
'Controller Namespaces',
|
|
342
|
+
'namespace-list',
|
|
343
|
+
renderControllerNamespaceFilters()
|
|
344
|
+
);
|
|
345
|
+
methodFilter.innerHTML = sectionHtml(
|
|
346
|
+
'Controller Filters',
|
|
347
|
+
'namespace-list methods-list',
|
|
348
|
+
renderControllerFlagFilters()
|
|
349
|
+
);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (currentView === 'models') {
|
|
354
|
+
namespaceFilter.style.opacity = '1';
|
|
355
|
+
namespaceFilter.style.pointerEvents = 'auto';
|
|
356
|
+
methodFilter.style.opacity = '1';
|
|
357
|
+
methodFilter.style.pointerEvents = 'auto';
|
|
358
|
+
|
|
359
|
+
namespaceFilter.innerHTML = sectionHtml(
|
|
360
|
+
'Model Namespaces',
|
|
361
|
+
'namespace-list',
|
|
362
|
+
renderModelNamespaceFilters()
|
|
363
|
+
);
|
|
364
|
+
methodFilter.innerHTML = sectionHtml(
|
|
365
|
+
'Model Filters',
|
|
366
|
+
'namespace-list methods-list',
|
|
367
|
+
renderModelFlagFilters()
|
|
368
|
+
);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (currentView === 'grpc') {
|
|
373
|
+
namespaceFilter.style.opacity = '1';
|
|
374
|
+
namespaceFilter.style.pointerEvents = 'auto';
|
|
375
|
+
methodFilter.style.opacity = '1';
|
|
376
|
+
methodFilter.style.pointerEvents = 'auto';
|
|
377
|
+
|
|
378
|
+
namespaceFilter.innerHTML = sectionHtml(
|
|
379
|
+
'gRPC Namespaces',
|
|
380
|
+
'namespace-list',
|
|
381
|
+
renderGrpcNamespaceFilters()
|
|
382
|
+
);
|
|
383
|
+
methodFilter.innerHTML = sectionHtml(
|
|
384
|
+
'gRPC Filters',
|
|
385
|
+
'namespace-list methods-list',
|
|
386
|
+
renderGrpcFlagFilters()
|
|
387
|
+
);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// diagram: keep disabled (no meaningful sidebar filters)
|
|
392
|
+
namespaceFilter.style.opacity = '0.4';
|
|
393
|
+
namespaceFilter.style.pointerEvents = 'none';
|
|
394
|
+
methodFilter.style.opacity = '0.4';
|
|
395
|
+
methodFilter.style.pointerEvents = 'none';
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function escapeHtml(s) {
|
|
399
|
+
return String(s)
|
|
400
|
+
.replace(/&/g, '&')
|
|
401
|
+
.replace(/</g, '<')
|
|
402
|
+
.replace(/>/g, '>')
|
|
403
|
+
.replace(/"/g, '"');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function renderFilterItem(label, count, filterType, filterValue, isActive) {
|
|
407
|
+
const safeLabel = escapeHtml(label);
|
|
408
|
+
const safeType = escapeHtml(filterType);
|
|
409
|
+
const safeValue = escapeHtml(filterValue);
|
|
410
|
+
return (
|
|
411
|
+
'<div class="namespace-item ' +
|
|
412
|
+
(isActive ? 'active' : '') +
|
|
413
|
+
'" data-filter-type="' +
|
|
414
|
+
safeType +
|
|
415
|
+
'" data-filter-value="' +
|
|
416
|
+
safeValue +
|
|
417
|
+
'">' +
|
|
418
|
+
'<span>' +
|
|
419
|
+
safeLabel +
|
|
420
|
+
'</span>' +
|
|
421
|
+
'<span class="namespace-count">' +
|
|
422
|
+
count +
|
|
423
|
+
'</span>' +
|
|
424
|
+
'</div>'
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function renderRouteNamespaceFilters() {
|
|
429
|
+
const counts = new Map();
|
|
430
|
+
routes.forEach(r => {
|
|
431
|
+
const ns = r.namespace || '';
|
|
432
|
+
counts.set(ns, (counts.get(ns) || 0) + 1);
|
|
433
|
+
});
|
|
434
|
+
const entries = [...counts.entries()].sort((a, b) => b[1] - a[1]);
|
|
435
|
+
const allCount = routes.length;
|
|
436
|
+
return [
|
|
437
|
+
renderFilterItem('All', allCount, 'routeNamespace', 'all', selectedNamespaces.has('all')),
|
|
438
|
+
...entries.map(([ns, count]) =>
|
|
439
|
+
renderFilterItem(ns || 'root', count, 'routeNamespace', ns, selectedNamespaces.has(ns))
|
|
440
|
+
),
|
|
441
|
+
].join('');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function renderControllerNamespaceFilters() {
|
|
445
|
+
const counts = new Map();
|
|
446
|
+
controllers.forEach(c => {
|
|
447
|
+
const ns = c.namespace || '';
|
|
448
|
+
counts.set(ns, (counts.get(ns) || 0) + 1);
|
|
449
|
+
});
|
|
450
|
+
const entries = [...counts.entries()].sort((a, b) => b[1] - a[1]);
|
|
451
|
+
const allCount = controllers.length;
|
|
452
|
+
return [
|
|
453
|
+
renderFilterItem('All', allCount, 'routeNamespace', 'all', selectedNamespaces.has('all')),
|
|
454
|
+
...entries.map(([ns, count]) =>
|
|
455
|
+
renderFilterItem(ns || 'root', count, 'routeNamespace', ns, selectedNamespaces.has(ns))
|
|
456
|
+
),
|
|
457
|
+
].join('');
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function renderRouteMethodFilters() {
|
|
461
|
+
const counts = new Map();
|
|
462
|
+
routes.forEach(r => {
|
|
463
|
+
const m = r.method || 'ALL';
|
|
464
|
+
counts.set(m, (counts.get(m) || 0) + 1);
|
|
465
|
+
});
|
|
466
|
+
const methods = ['ALL', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
|
467
|
+
const allCount = routes.length;
|
|
468
|
+
return methods.map(m => {
|
|
469
|
+
const label = m === 'ALL' ? 'All' : m;
|
|
470
|
+
const value = m === 'ALL' ? 'all' : m;
|
|
471
|
+
const count = m === 'ALL' ? allCount : (counts.get(m) || 0);
|
|
472
|
+
const active = selectedMethods.has(value);
|
|
473
|
+
return renderFilterItem(label, count, 'routeMethod', value, active);
|
|
474
|
+
}).join('');
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function renderControllerFlagFilters() {
|
|
478
|
+
const flags = [
|
|
479
|
+
{
|
|
480
|
+
key: 'json',
|
|
481
|
+
label: 'Renders JSON',
|
|
482
|
+
test: (c) => (c.actions || []).some((a) => a.rendersJson),
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
key: 'redirect',
|
|
486
|
+
label: 'Has Redirect',
|
|
487
|
+
test: (c) => (c.actions || []).some((a) => a.redirectsTo),
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
key: 'private',
|
|
491
|
+
label: 'Has Private Actions',
|
|
492
|
+
test: (c) => (c.actions || []).some((a) => a.visibility === 'private'),
|
|
493
|
+
},
|
|
494
|
+
];
|
|
495
|
+
const allCount = controllers.length;
|
|
496
|
+
const items = [
|
|
497
|
+
renderFilterItem('All', allCount, 'controllerFlag', 'all', selectedControllerFlags.has('all')),
|
|
498
|
+
];
|
|
499
|
+
flags.forEach(f => {
|
|
500
|
+
const count = controllers.filter(f.test).length;
|
|
501
|
+
items.push(renderFilterItem(f.label, count, 'controllerFlag', f.key, selectedControllerFlags.has(f.key)));
|
|
502
|
+
});
|
|
503
|
+
return items.join('');
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function getModelNamespace(model) {
|
|
507
|
+
const p = (model.filePath || '').split('/');
|
|
508
|
+
if (p.length <= 1) return '';
|
|
509
|
+
return p.slice(0, -1).join('/');
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function renderModelNamespaceFilters() {
|
|
513
|
+
const counts = new Map();
|
|
514
|
+
models.forEach(m => {
|
|
515
|
+
const ns = getModelNamespace(m);
|
|
516
|
+
counts.set(ns, (counts.get(ns) || 0) + 1);
|
|
517
|
+
});
|
|
518
|
+
const entries = [...counts.entries()].sort((a, b) => b[1] - a[1]);
|
|
519
|
+
const allCount = models.length;
|
|
520
|
+
return [
|
|
521
|
+
renderFilterItem('All', allCount, 'modelNamespace', 'all', selectedModelNamespaces.has('all')),
|
|
522
|
+
...entries.map(([ns, count]) =>
|
|
523
|
+
renderFilterItem(ns || 'root', count, 'modelNamespace', ns, selectedModelNamespaces.has(ns))
|
|
524
|
+
),
|
|
525
|
+
].join('');
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function renderModelFlagFilters() {
|
|
529
|
+
const flags = [
|
|
530
|
+
{ key: 'assoc', label: 'Has associations', test: (m) => (m.associations || []).length > 0 },
|
|
531
|
+
{ key: 'valid', label: 'Has validations', test: (m) => (m.validations || []).length > 0 },
|
|
532
|
+
{ key: 'cb', label: 'Has callbacks', test: (m) => (m.callbacks || []).length > 0 },
|
|
533
|
+
{ key: 'concern', label: 'Includes concerns', test: (m) => (m.concerns || []).length > 0 },
|
|
534
|
+
{ key: 'enum', label: 'Has enums', test: (m) => (m.enums || []).length > 0 },
|
|
535
|
+
];
|
|
536
|
+
const allCount = models.length;
|
|
537
|
+
const items = [
|
|
538
|
+
renderFilterItem('All', allCount, 'modelFlag', 'all', selectedModelFlags.has('all')),
|
|
539
|
+
];
|
|
540
|
+
flags.forEach(f => {
|
|
541
|
+
const count = models.filter(f.test).length;
|
|
542
|
+
items.push(renderFilterItem(f.label, count, 'modelFlag', f.key, selectedModelFlags.has(f.key)));
|
|
543
|
+
});
|
|
544
|
+
return items.join('');
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function renderGrpcNamespaceFilters() {
|
|
548
|
+
const counts = new Map();
|
|
549
|
+
grpcServices.forEach(s => {
|
|
550
|
+
const ns = s.namespace || '';
|
|
551
|
+
counts.set(ns, (counts.get(ns) || 0) + 1);
|
|
552
|
+
});
|
|
553
|
+
const entries = [...counts.entries()].sort((a, b) => b[1] - a[1]);
|
|
554
|
+
const allCount = grpcServices.length;
|
|
555
|
+
return [
|
|
556
|
+
renderFilterItem('All', allCount, 'grpcNamespace', 'all', selectedGrpcNamespaces.has('all')),
|
|
557
|
+
...entries.map(([ns, count]) =>
|
|
558
|
+
renderFilterItem(ns || 'root', count, 'grpcNamespace', ns, selectedGrpcNamespaces.has(ns))
|
|
559
|
+
),
|
|
560
|
+
].join('');
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function renderGrpcFlagFilters() {
|
|
564
|
+
const flags = [
|
|
565
|
+
{ key: 'policies', label: 'Has policies', test: (s) => (s.policies || []).length > 0 },
|
|
566
|
+
{ key: 'serializers', label: 'Has serializers', test: (s) => (s.serializers || []).length > 0 },
|
|
567
|
+
{ key: 'concerns', label: 'Includes concerns', test: (s) => (s.concerns || []).length > 0 },
|
|
568
|
+
{ key: 'modelsUsed', label: 'RPC uses models', test: (s) => (s.rpcs || []).some(r => (r.modelsUsed || []).length > 0) },
|
|
569
|
+
{ key: 'servicesUsed', label: 'RPC uses services', test: (s) => (s.rpcs || []).some(r => (r.servicesUsed || []).length > 0) },
|
|
570
|
+
];
|
|
571
|
+
const allCount = grpcServices.length;
|
|
572
|
+
const items = [
|
|
573
|
+
renderFilterItem('All', allCount, 'grpcFlag', 'all', selectedGrpcFlags.has('all')),
|
|
574
|
+
];
|
|
575
|
+
flags.forEach(f => {
|
|
576
|
+
const count = grpcServices.filter(f.test).length;
|
|
577
|
+
items.push(renderFilterItem(f.label, count, 'grpcFlag', f.key, selectedGrpcFlags.has(f.key)));
|
|
578
|
+
});
|
|
579
|
+
return items.join('');
|
|
580
|
+
}
|
|
581
|
+
|
|
288
582
|
function filterRoutes() {
|
|
289
583
|
return routes.filter(route => {
|
|
290
584
|
// Namespace filter (multi-select)
|
|
@@ -355,6 +649,18 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
355
649
|
if (!selectedNamespaces.has('all')) {
|
|
356
650
|
filteredControllers = filteredControllers.filter(c => selectedNamespaces.has(c.namespace || ''));
|
|
357
651
|
}
|
|
652
|
+
if (!selectedControllerFlags.has('all')) {
|
|
653
|
+
filteredControllers = filteredControllers.filter((c) => {
|
|
654
|
+
const rendersJson = (c.actions || []).some((a) => a.rendersJson);
|
|
655
|
+
const hasRedirect = (c.actions || []).some((a) => a.redirectsTo);
|
|
656
|
+
const hasPrivate = (c.actions || []).some((a) => a.visibility === 'private');
|
|
657
|
+
|
|
658
|
+
if (selectedControllerFlags.has('json') && !rendersJson) return false;
|
|
659
|
+
if (selectedControllerFlags.has('redirect') && !hasRedirect) return false;
|
|
660
|
+
if (selectedControllerFlags.has('private') && !hasPrivate) return false;
|
|
661
|
+
return true;
|
|
662
|
+
});
|
|
663
|
+
}
|
|
358
664
|
const displayed = filteredControllers.slice(0, controllersDisplayCount);
|
|
359
665
|
const hasMore = filteredControllers.length > controllersDisplayCount;
|
|
360
666
|
|
|
@@ -406,6 +712,27 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
406
712
|
m.className.toLowerCase().includes(searchQuery)
|
|
407
713
|
);
|
|
408
714
|
}
|
|
715
|
+
// Model namespace filter
|
|
716
|
+
if (!selectedModelNamespaces.has('all')) {
|
|
717
|
+
filteredModels = filteredModels.filter(m => selectedModelNamespaces.has(getModelNamespace(m)));
|
|
718
|
+
}
|
|
719
|
+
// Model flag filter
|
|
720
|
+
if (!selectedModelFlags.has('all')) {
|
|
721
|
+
filteredModels = filteredModels.filter(m => {
|
|
722
|
+
const hasAssoc = (m.associations || []).length > 0;
|
|
723
|
+
const hasValid = (m.validations || []).length > 0;
|
|
724
|
+
const hasCb = (m.callbacks || []).length > 0;
|
|
725
|
+
const hasConcern = (m.concerns || []).length > 0;
|
|
726
|
+
const hasEnum = (m.enums || []).length > 0;
|
|
727
|
+
|
|
728
|
+
if (selectedModelFlags.has('assoc') && !hasAssoc) return false;
|
|
729
|
+
if (selectedModelFlags.has('valid') && !hasValid) return false;
|
|
730
|
+
if (selectedModelFlags.has('cb') && !hasCb) return false;
|
|
731
|
+
if (selectedModelFlags.has('concern') && !hasConcern) return false;
|
|
732
|
+
if (selectedModelFlags.has('enum') && !hasEnum) return false;
|
|
733
|
+
return true;
|
|
734
|
+
});
|
|
735
|
+
}
|
|
409
736
|
const displayed = filteredModels.slice(0, modelsDisplayCount);
|
|
410
737
|
const hasMore = filteredModels.length > modelsDisplayCount;
|
|
411
738
|
|
|
@@ -431,6 +758,7 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
431
758
|
\${hasMore ? \`
|
|
432
759
|
<div class="show-more-container">
|
|
433
760
|
<button class="show-more-btn" onclick="loadMoreModels()">Show More (+50)</button>
|
|
761
|
+
<button class="show-more-btn" onclick="showAllModels()">Show All</button>
|
|
434
762
|
<span class="show-more-count">\${modelsDisplayCount} / \${filteredModels.length}</span>
|
|
435
763
|
</div>
|
|
436
764
|
\` : ''}
|
|
@@ -442,6 +770,11 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
442
770
|
renderMainPanel();
|
|
443
771
|
};
|
|
444
772
|
|
|
773
|
+
window.showAllModels = function() {
|
|
774
|
+
modelsDisplayCount = filteredModels.length;
|
|
775
|
+
renderMainPanel();
|
|
776
|
+
};
|
|
777
|
+
|
|
445
778
|
let grpcDisplayCount = 50;
|
|
446
779
|
let filteredGrpc = grpcServices;
|
|
447
780
|
|
|
@@ -454,6 +787,25 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
454
787
|
(svc.rpcs && svc.rpcs.some(rpc => rpc.name && rpc.name.toLowerCase().includes(searchQuery)))
|
|
455
788
|
);
|
|
456
789
|
}
|
|
790
|
+
if (!selectedGrpcNamespaces.has('all')) {
|
|
791
|
+
filteredGrpc = filteredGrpc.filter(svc => selectedGrpcNamespaces.has(svc.namespace || ''));
|
|
792
|
+
}
|
|
793
|
+
if (!selectedGrpcFlags.has('all')) {
|
|
794
|
+
filteredGrpc = filteredGrpc.filter(svc => {
|
|
795
|
+
const hasPolicies = (svc.policies || []).length > 0;
|
|
796
|
+
const hasSerializers = (svc.serializers || []).length > 0;
|
|
797
|
+
const hasConcerns = (svc.concerns || []).length > 0;
|
|
798
|
+
const usesModels = (svc.rpcs || []).some(r => (r.modelsUsed || []).length > 0);
|
|
799
|
+
const usesServices = (svc.rpcs || []).some(r => (r.servicesUsed || []).length > 0);
|
|
800
|
+
|
|
801
|
+
if (selectedGrpcFlags.has('policies') && !hasPolicies) return false;
|
|
802
|
+
if (selectedGrpcFlags.has('serializers') && !hasSerializers) return false;
|
|
803
|
+
if (selectedGrpcFlags.has('concerns') && !hasConcerns) return false;
|
|
804
|
+
if (selectedGrpcFlags.has('modelsUsed') && !usesModels) return false;
|
|
805
|
+
if (selectedGrpcFlags.has('servicesUsed') && !usesServices) return false;
|
|
806
|
+
return true;
|
|
807
|
+
});
|
|
808
|
+
}
|
|
457
809
|
|
|
458
810
|
const displayedGrpc = filteredGrpc.slice(0, grpcDisplayCount);
|
|
459
811
|
|
|
@@ -461,7 +813,7 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
461
813
|
<div class="panel-header">
|
|
462
814
|
<div class="panel-title">gRPC Services <span class="panel-count">(\${Math.min(grpcDisplayCount, filteredGrpc.length)} / \${filteredGrpc.length})</span></div>
|
|
463
815
|
</div>
|
|
464
|
-
<div
|
|
816
|
+
<div class="model-card-grid">
|
|
465
817
|
\${displayedGrpc.map((svc, idx) => \`
|
|
466
818
|
<div class="model-card" onclick="showGrpcDetail(\${idx})">
|
|
467
819
|
<div class="model-name">
|
|
@@ -1419,5 +1771,5 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';
|
|
|
1419
1771
|
`).join("")}
|
|
1420
1772
|
</tbody>
|
|
1421
1773
|
</table>
|
|
1422
|
-
`}highlightParams(t){return t.replace(/:([a-zA-Z_]+)/g,'<span class="param">:$1</span>')}};async function m(){let o=process.argv[2]||process.cwd(),t=process.argv[3]||
|
|
1423
|
-
export{
|
|
1774
|
+
`}highlightParams(t){return t.replace(/:([a-zA-Z_]+)/g,'<span class="param">:$1</span>')}};async function m(){let o=process.argv[2]||process.cwd(),t=process.argv[3]||d.join(o,"rails-map.html");await new i(o).generate({title:"Rails Application Map",outputPath:t});}var p=import.meta.url===`file://${process.argv[1]}`;p&&m().catch(console.error);
|
|
1775
|
+
export{i as a};
|