modviz 0.1.2

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.
Files changed (109) hide show
  1. package/README.md +261 -0
  2. package/dist/client/_shell.html +0 -0
  3. package/dist/client/android-chrome-192x192.png +0 -0
  4. package/dist/client/android-chrome-512x512.png +0 -0
  5. package/dist/client/apple-touch-icon.png +0 -0
  6. package/dist/client/assets/app-Sjrldkrg.css +2 -0
  7. package/dist/client/assets/button-aOWckyNs.js +1 -0
  8. package/dist/client/assets/check-C0EQe2S8.js +1 -0
  9. package/dist/client/assets/chevron-down-DrspihmT.js +1 -0
  10. package/dist/client/assets/chevron-right-DIJHr8AN.js +1 -0
  11. package/dist/client/assets/colors-CQoWjU5E.js +1 -0
  12. package/dist/client/assets/command-kkF7_wdz.js +45 -0
  13. package/dist/client/assets/compare-K6jVFsiI.js +1 -0
  14. package/dist/client/assets/compare-TOnoe1EP.js +2 -0
  15. package/dist/client/assets/configure-DnlSnhtN.js +1 -0
  16. package/dist/client/assets/explorer-C7NclVKg.js +2 -0
  17. package/dist/client/assets/explorer-Xu2X6XXF.js +1 -0
  18. package/dist/client/assets/external-link-B9eNA-li.js +1 -0
  19. package/dist/client/assets/flamegraph-CRVZSAlj.js +13 -0
  20. package/dist/client/assets/floating-ui.dom-DLIT5tPE.js +1 -0
  21. package/dist/client/assets/formatting-CiC0SYI8.js +1 -0
  22. package/dist/client/assets/graph-6Vr74V1k.js +2 -0
  23. package/dist/client/assets/graph-CVzypIGU.js +2 -0
  24. package/dist/client/assets/graph-command-menu-D2MoVT2B.js +4 -0
  25. package/dist/client/assets/graph-command-menu-VWiiW3qy.css +1 -0
  26. package/dist/client/assets/hierarchy-C8xxGb_u.js +2 -0
  27. package/dist/client/assets/hierarchy-iO7d4oSK.js +2 -0
  28. package/dist/client/assets/import-display-D-jRyyjM.js +5 -0
  29. package/dist/client/assets/imports-CPggnrs-.js +2 -0
  30. package/dist/client/assets/imports-CodbPyUJ.js +1 -0
  31. package/dist/client/assets/index-Dj_rhLdR.js +12 -0
  32. package/dist/client/assets/input-BCFMF0aR.js +1 -0
  33. package/dist/client/assets/jsx-runtime-DWSWI4JT.js +1 -0
  34. package/dist/client/assets/lazyRouteComponent-PTSyFp1J.js +1 -0
  35. package/dist/client/assets/loading-state-CyC_hrTF.js +1 -0
  36. package/dist/client/assets/modviz-data-BiRqoDI5.js +1 -0
  37. package/dist/client/assets/modviz-layout-Do93E-IB.js +1 -0
  38. package/dist/client/assets/modviz-sigma-Xl8qHaxK.js +312 -0
  39. package/dist/client/assets/portal-BgAm3V3j.js +1 -0
  40. package/dist/client/assets/routes-DBtN8hrZ.js +1 -0
  41. package/dist/client/assets/schemas-B4zfTepZ.js +39 -0
  42. package/dist/client/assets/search-BYHxNrYn.js +1 -0
  43. package/dist/client/assets/search-params-BaZRBvGI.js +1 -0
  44. package/dist/client/assets/setup-view-j1o0TuZz.js +1 -0
  45. package/dist/client/assets/summary-D703Zh3x.js +1 -0
  46. package/dist/client/assets/tooltip-B1VDU9HG.js +1 -0
  47. package/dist/client/assets/trace-B67CM5s2.js +2 -0
  48. package/dist/client/assets/trace-Bwwdw3AM.js +1 -0
  49. package/dist/client/assets/treemap-BZf2shzY.js +5 -0
  50. package/dist/client/assets/treemap-Csroy8Gy.js +2 -0
  51. package/dist/client/assets/utils-DkkZd0ys.js +1 -0
  52. package/dist/client/favicon-16x16.png +0 -0
  53. package/dist/client/favicon-32x32.png +0 -0
  54. package/dist/client/favicon.ico +0 -0
  55. package/dist/client/favicon.png +0 -0
  56. package/dist/client/site.webmanifest +19 -0
  57. package/dist/mod/cli-options.js +225 -0
  58. package/dist/mod/cli.js +519 -0
  59. package/dist/mod/index.js +3 -0
  60. package/dist/mod/llm-analysis.js +29 -0
  61. package/dist/mod/llm-output.js +742 -0
  62. package/dist/mod/module-graph-plugins.js +60 -0
  63. package/dist/mod/production-server.js +103 -0
  64. package/dist/mod/runtime-host.js +217 -0
  65. package/dist/mod/snapshot-history.js +73 -0
  66. package/dist/mod/types.js +3 -0
  67. package/dist/server/assets/__23tanstack-start-plugin-adapters-3QxJs4a0.js +5 -0
  68. package/dist/server/assets/_tanstack-start-manifest_v-DMytuIue.js +188 -0
  69. package/dist/server/assets/button-Bqnnid5i.js +41 -0
  70. package/dist/server/assets/colors-DhAxrYua.js +100 -0
  71. package/dist/server/assets/command-SdxShIbL.js +138 -0
  72. package/dist/server/assets/compare-BFMiiUsB.js +562 -0
  73. package/dist/server/assets/compare-CpOqTpYu.js +10 -0
  74. package/dist/server/assets/configure-Bvd45DTI.js +288 -0
  75. package/dist/server/assets/explorer-C7dODpSv.js +379 -0
  76. package/dist/server/assets/explorer-CpSb0JTa.js +20 -0
  77. package/dist/server/assets/flamegraph-CdW-VG6I.js +198 -0
  78. package/dist/server/assets/formatting-iDlL4tA-.js +4 -0
  79. package/dist/server/assets/graph-C1G9H5O4.js +438 -0
  80. package/dist/server/assets/graph-DAGFGioS.js +45 -0
  81. package/dist/server/assets/graph-command-menu-BV5GtOWx.js +249 -0
  82. package/dist/server/assets/hierarchy-B4K-Zfn9.js +16 -0
  83. package/dist/server/assets/hierarchy-BGpWSG-f.js +104 -0
  84. package/dist/server/assets/import-display-BVIOWcsm.js +124 -0
  85. package/dist/server/assets/imports-B6JBDl_h.js +379 -0
  86. package/dist/server/assets/imports-BGe5tZJT.js +28 -0
  87. package/dist/server/assets/input-C5r-hBix.js +19 -0
  88. package/dist/server/assets/loading-state-CrvCWTtw.js +23 -0
  89. package/dist/server/assets/modviz-data-CUyTorv0.js +197 -0
  90. package/dist/server/assets/modviz-layout-BAH2ogse.js +253 -0
  91. package/dist/server/assets/modviz-server-DoMlAyFW.js +195 -0
  92. package/dist/server/assets/modviz-sigma-XYxARWqd.js +1441 -0
  93. package/dist/server/assets/rolldown-runtime-rSIU-vHC.js +13 -0
  94. package/dist/server/assets/router-DYJ-zDbU.js +353 -0
  95. package/dist/server/assets/routes-DInCacpY.js +244 -0
  96. package/dist/server/assets/search-params-BNApPgkX.js +26 -0
  97. package/dist/server/assets/setup-view-DjI49Iqr.js +91 -0
  98. package/dist/server/assets/start-Ba3KII43.js +4 -0
  99. package/dist/server/assets/summary-z3lXkLCQ.js +208 -0
  100. package/dist/server/assets/tooltip-Ck0DDfF7.js +24 -0
  101. package/dist/server/assets/trace-ColKOf9g.js +16 -0
  102. package/dist/server/assets/trace-eVs-hIZO.js +578 -0
  103. package/dist/server/assets/treemap-BbZ9M4GF.js +17 -0
  104. package/dist/server/assets/treemap-CrgWFoCF.js +912 -0
  105. package/dist/server/assets/utils-BQZm0uva.js +8 -0
  106. package/dist/server/server.js +5259 -0
  107. package/dist/shared/modviz-compare.js +120 -0
  108. package/dist/shared/modviz-trace.js +244 -0
  109. package/package.json +135 -0
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "",
3
+ "short_name": "",
4
+ "icons": [
5
+ {
6
+ "src": "/android-chrome-192x192.png",
7
+ "sizes": "192x192",
8
+ "type": "image/png"
9
+ },
10
+ {
11
+ "src": "/android-chrome-512x512.png",
12
+ "sizes": "512x512",
13
+ "type": "image/png"
14
+ }
15
+ ],
16
+ "theme_color": "#ffffff",
17
+ "background_color": "#ffffff",
18
+ "display": "standalone"
19
+ }
@@ -0,0 +1,225 @@
1
+ const valueOptionNames = new Set([
2
+ "--port",
3
+ "--llm-base-url",
4
+ "--llm-model",
5
+ "--output-file",
6
+ "--barrel-threshold",
7
+ "--exclude",
8
+ "--history-dir",
9
+ "--include",
10
+ "--package",
11
+ "--node",
12
+ "--limit",
13
+ "--graph-file",
14
+ "--snapshot-name",
15
+ "--snapshot",
16
+ ]);
17
+ const parseOptionTokens = (args) => {
18
+ const flags = new Set();
19
+ const values = new Map();
20
+ const missingValueOptions = [];
21
+ const positionals = [];
22
+ for (let index = 0; index < args.length; index += 1) {
23
+ const currentArg = args[index];
24
+ if (!currentArg) {
25
+ continue;
26
+ }
27
+ if (currentArg === "--") {
28
+ positionals.push(...args.slice(index + 1));
29
+ break;
30
+ }
31
+ if (!currentArg.startsWith("--")) {
32
+ positionals.push(currentArg);
33
+ continue;
34
+ }
35
+ if (currentArg.startsWith("--no-")) {
36
+ flags.add(currentArg);
37
+ continue;
38
+ }
39
+ const equalSignIndex = currentArg.indexOf("=");
40
+ const optionName = equalSignIndex === -1 ? currentArg : currentArg.slice(0, equalSignIndex);
41
+ if (equalSignIndex !== -1) {
42
+ values.set(optionName, currentArg.slice(equalSignIndex + 1));
43
+ continue;
44
+ }
45
+ if (valueOptionNames.has(optionName)) {
46
+ const nextArg = args[index + 1];
47
+ if (nextArg && nextArg !== "--" && !nextArg.startsWith("--")) {
48
+ values.set(optionName, nextArg);
49
+ index += 1;
50
+ }
51
+ else {
52
+ missingValueOptions.push(optionName);
53
+ }
54
+ continue;
55
+ }
56
+ flags.add(optionName);
57
+ }
58
+ return { flags, values, missingValueOptions, positionals };
59
+ };
60
+ export function parseCliArgs(args) {
61
+ const [firstArg, ...restArgs] = args;
62
+ const command = firstArg === "analyze" || firstArg === "serve" || firstArg === "report" || firstArg === "diff"
63
+ ? firstArg
64
+ : "analyze";
65
+ const commandArgs = command === "analyze" && firstArg !== "analyze" ? args : restArgs;
66
+ const { flags: parsedFlags, values: parsedValues, missingValueOptions, positionals, } = parseOptionTokens(commandArgs);
67
+ const serve = args.includes("--serve");
68
+ const effectiveServe = command === "serve" || serve;
69
+ const getOptionValue = (name) => parsedValues.get(name);
70
+ const hasFlag = (name) => parsedFlags.has(name);
71
+ return {
72
+ command,
73
+ entryFile: effectiveServe || command === "report" ? undefined : positionals[0],
74
+ serveDataFile: effectiveServe ? positionals[0] : undefined,
75
+ flags: {
76
+ port: getOptionValue("--port") ?? "3628",
77
+ open: !hasFlag("--no-open"),
78
+ ui: hasFlag("--ui"),
79
+ barrelThreshold: Number.parseInt(getOptionValue("--barrel-threshold") ?? "3", 10),
80
+ exclude: getOptionValue("--exclude"),
81
+ historyDir: getOptionValue("--history-dir"),
82
+ include: getOptionValue("--include"),
83
+ llmAnalyze: hasFlag("--llm-analyze"),
84
+ llmBaseUrl: getOptionValue("--llm-base-url"),
85
+ llmModel: getOptionValue("--llm-model"),
86
+ outputFile: getOptionValue("--output-file") ?? "./modviz.json",
87
+ nodeModules: hasFlag("--node-modules"),
88
+ ignoreDynamic: hasFlag("--ignore-dynamic"),
89
+ ignoreTypeOnly: hasFlag("--ignore-type-only"),
90
+ serve: effectiveServe,
91
+ help: commandArgs.includes("--help") || commandArgs.includes("-h"),
92
+ llm: hasFlag("--llm"),
93
+ packageQuery: getOptionValue("--package"),
94
+ nodeQuery: getOptionValue("--node"),
95
+ limit: Number.parseInt(getOptionValue("--limit") ?? "20", 10),
96
+ summary: hasFlag("--summary"),
97
+ graphFile: getOptionValue("--graph-file"),
98
+ snapshotName: getOptionValue("--snapshot-name"),
99
+ snapshot: getOptionValue("--snapshot"),
100
+ listSnapshots: hasFlag("--list-snapshots"),
101
+ },
102
+ missingValueOptions,
103
+ positionals,
104
+ };
105
+ }
106
+ export function validateCliArgs(parsedArgs) {
107
+ const { command, entryFile, flags, missingValueOptions = [] } = parsedArgs;
108
+ if (missingValueOptions.length > 0) {
109
+ return `Missing value for ${missingValueOptions[0]}`;
110
+ }
111
+ if (command === "analyze" && !flags.serve && !entryFile && !flags.help) {
112
+ return "Entry file is required when not using --serve.";
113
+ }
114
+ if (command === "report" &&
115
+ !flags.summary &&
116
+ !flags.packageQuery &&
117
+ !flags.nodeQuery &&
118
+ !flags.listSnapshots &&
119
+ !flags.help) {
120
+ return "Report command requires --summary, --package, --node, or --list-snapshots.";
121
+ }
122
+ if (command === "diff" && !flags.help && (parsedArgs.positionals?.length ?? 0) < 2) {
123
+ return "Diff command requires <baseline> and <current> graph targets.";
124
+ }
125
+ if (flags.port && Number.isNaN(Number.parseInt(flags.port, 10))) {
126
+ return `Invalid --port value: ${flags.port}`;
127
+ }
128
+ if (!Number.isFinite(flags.limit) || flags.limit < 1) {
129
+ return `Invalid --limit value: ${flags.limit}`;
130
+ }
131
+ if (!Number.isFinite(flags.barrelThreshold) || flags.barrelThreshold < 1) {
132
+ return `Invalid --barrel-threshold value: ${flags.barrelThreshold}`;
133
+ }
134
+ return null;
135
+ }
136
+ export function buildCliHelpText() {
137
+ return `
138
+ modviz - Module dependency graph visualizer and import analysis CLI
139
+
140
+ Usage:
141
+ modviz analyze <entryFile> Generate graph JSON for the UI
142
+ modviz serve [dataFile] Launch the web UI with existing graph data
143
+ modviz report --summary Print a concise terminal summary from an existing graph file
144
+ modviz diff <baseline> <current> Print graph deltas between two graph files or snapshot:<id> targets
145
+ modviz report --package=zod Print origin traces for one external package
146
+ modviz report --node=src/foo.ts Print origin traces for one node
147
+ modviz report --list-snapshots Show named snapshot history
148
+ modviz <entryFile> Legacy shorthand for analyze <entryFile>
149
+
150
+ Options:
151
+ --output-file=<file> Base JSON output path for the UI graph (default: ./modviz.json)
152
+ --graph-file=<file> Existing graph file used by report (default: ./modviz.json)
153
+ --port=<port> Port for the web server (default: 3628)
154
+ --no-open Do not open a browser window when launching the UI
155
+ --ui Launch the browser UI after generating the graph
156
+ --barrel-threshold=<n> Export count that marks a file as a barrel file (default: 3)
157
+ --include=<glob,...> Keep only matching paths in the generated graph
158
+ --exclude=<glob,...> Drop matching paths from the generated graph
159
+ --history-dir=<dir> Override the snapshot history directory for report, diff, and saved snapshots
160
+ --serve Launch the UI server using an existing graph JSON file
161
+ --llm Also emit <output>.llm.json and <output>.llm.md focused on import origins and barrel-file impact
162
+ --llm-analyze Use the Vercel AI SDK to turn the structured LLM report into <output>.llm.ai.md
163
+ --llm-model=<model> Override the OpenAI-compatible model used by --llm-analyze
164
+ --llm-base-url=<url> Override the OpenAI-compatible base URL used by --llm-analyze
165
+ --package=<name> Focus outputs and drilldowns on one external package
166
+ --node=<path> Focus outputs and drilldowns on one node path or display path
167
+ --limit=<n> Limit printed drilldown lists and cap stored origin chains per node (default: 5)
168
+ --summary Print a terminal summary of the generated graph
169
+ --snapshot-name=<name> Save the generated snapshot into history under a named run
170
+ --snapshot=<id> Load a named history snapshot for report
171
+ --list-snapshots List available named snapshots
172
+ --node-modules Keep node_modules in the analyzed graph instead of excluding them
173
+ --ignore-dynamic Ignore dynamic imports
174
+ --ignore-type-only Ignore type-only imports
175
+ --help, -h Show this help message
176
+
177
+ Examples:
178
+ modviz analyze src/index.ts --ui --port=4000
179
+ modviz analyze src/index.ts --llm --snapshot-name=before-refactor
180
+ modviz analyze src/index.ts --barrel-threshold=5
181
+ modviz analyze src/index.ts --include='src/routes/**,src/components/**' --exclude='**/*.test.ts'
182
+ modviz analyze src/index.ts --node-modules --package=googleapis
183
+ modviz serve ./modviz.json
184
+ modviz report --summary
185
+ modviz diff snapshot:before-refactor ./modviz.json
186
+ modviz report --snapshot=2026-04-01t12-00-00-before-refactor --package=googleapis
187
+ modviz report --list-snapshots
188
+ `;
189
+ }
190
+ const getExternalPackageName = (node) => {
191
+ const segments = node.path.split(/[\\/]/).filter(Boolean);
192
+ const nodeModulesIndex = segments.lastIndexOf("node_modules");
193
+ if (nodeModulesIndex === -1) {
194
+ return node.package?.name ?? "external";
195
+ }
196
+ const scopeOrName = segments[nodeModulesIndex + 1];
197
+ const maybeName = segments[nodeModulesIndex + 2];
198
+ if (!scopeOrName) {
199
+ return "node_modules";
200
+ }
201
+ return scopeOrName.startsWith("@") && maybeName ? `${scopeOrName}/${maybeName}` : scopeOrName;
202
+ };
203
+ export function buildCliSummary(output) {
204
+ const workspaceNodes = output.nodes.filter((node) => node.type !== "external");
205
+ const externalNodes = output.nodes.filter((node) => node.type === "external");
206
+ const externalPackages = new Set(externalNodes.map((node) => getExternalPackageName(node)));
207
+ return [
208
+ "",
209
+ "Graph summary",
210
+ `- Nodes: ${output.nodes.length} total (${workspaceNodes.length} workspace, ${externalNodes.length} external)`,
211
+ `- Edges: ${output.imports.length}`,
212
+ `- Workspace packages: ${output.metadata.packages.length}`,
213
+ `- External packages: ${externalPackages.size}`,
214
+ `- Barrel files: ${output.nodes.filter((node) => node.isBarrelFile).length}`,
215
+ `- Entrypoints: ${output.metadata.entrypoints.join(", ") || "none"}`,
216
+ ].join("\n");
217
+ }
218
+ export function buildSnapshotList(history) {
219
+ if (history.length === 0) {
220
+ return "No named snapshots found.\n";
221
+ }
222
+ return `${history
223
+ .map((snapshot) => `- ${snapshot.id} (${snapshot.totalNodes} nodes${snapshot.generatedAt ? `, generated ${snapshot.generatedAt}` : ""})`)
224
+ .join("\n")}\n`;
225
+ }