@odoograph/cli 0.1.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.
Files changed (54) hide show
  1. package/README.md +118 -0
  2. package/dist/cache.d.ts +35 -0
  3. package/dist/cache.d.ts.map +1 -0
  4. package/dist/cache.js +108 -0
  5. package/dist/cache.js.map +1 -0
  6. package/dist/cache.test.d.ts +5 -0
  7. package/dist/cache.test.d.ts.map +1 -0
  8. package/dist/cache.test.js +54 -0
  9. package/dist/cache.test.js.map +1 -0
  10. package/dist/commands/gaps.d.ts +6 -0
  11. package/dist/commands/gaps.d.ts.map +1 -0
  12. package/dist/commands/gaps.js +87 -0
  13. package/dist/commands/gaps.js.map +1 -0
  14. package/dist/commands/graph.d.ts +6 -0
  15. package/dist/commands/graph.d.ts.map +1 -0
  16. package/dist/commands/graph.js +36 -0
  17. package/dist/commands/graph.js.map +1 -0
  18. package/dist/commands/lint.d.ts +6 -0
  19. package/dist/commands/lint.d.ts.map +1 -0
  20. package/dist/commands/lint.js +56 -0
  21. package/dist/commands/lint.js.map +1 -0
  22. package/dist/commands/parse.d.ts +6 -0
  23. package/dist/commands/parse.d.ts.map +1 -0
  24. package/dist/commands/parse.js +60 -0
  25. package/dist/commands/parse.js.map +1 -0
  26. package/dist/commands/workspace.d.ts +6 -0
  27. package/dist/commands/workspace.d.ts.map +1 -0
  28. package/dist/commands/workspace.js +113 -0
  29. package/dist/commands/workspace.js.map +1 -0
  30. package/dist/config.d.ts +36 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +104 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/config.test.d.ts +5 -0
  35. package/dist/config.test.d.ts.map +1 -0
  36. package/dist/config.test.js +76 -0
  37. package/dist/config.test.js.map +1 -0
  38. package/dist/index.d.ts +13 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +42 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/output.d.ts +27 -0
  43. package/dist/output.d.ts.map +1 -0
  44. package/dist/output.js +114 -0
  45. package/dist/output.js.map +1 -0
  46. package/dist/progress.d.ts +29 -0
  47. package/dist/progress.d.ts.map +1 -0
  48. package/dist/progress.js +65 -0
  49. package/dist/progress.js.map +1 -0
  50. package/dist/utils.d.ts +24 -0
  51. package/dist/utils.d.ts.map +1 -0
  52. package/dist/utils.js +104 -0
  53. package/dist/utils.js.map +1 -0
  54. package/package.json +53 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Workspace command - build cross-module graph with full analysis
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const workspaceCommand: Command;
6
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/commands/workspace.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,eAAO,MAAM,gBAAgB,SAoHzB,CAAC"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Workspace command - build cross-module graph with full analysis
3
+ */
4
+ import { Command } from "commander";
5
+ import { OdooGraph } from "@odoograph/wasm";
6
+ import { formatOutput, formatStats, formatGapReport } from "../output.js";
7
+ import { loadCache, saveCache, getCacheKey } from "../cache.js";
8
+ import { createProgress } from "../progress.js";
9
+ import { resolvePaths } from "../config.js";
10
+ export const workspaceCommand = new Command("workspace")
11
+ .description("Build cross-module workspace graph")
12
+ .option("-w, --workspace <paths...>", "Workspace addon paths (analyzed)")
13
+ .option("-e, --external <paths...>", "External addon paths (for resolution)")
14
+ .option("-c, --config <file>", "Odoo config file (odoo.conf) to read addons_path")
15
+ .option("-f, --format <format>", "Output format: json, human", "human")
16
+ .option("--gaps", "Run gap detection after building", false)
17
+ .option("--lint", "Run linting after building", false)
18
+ .option("--save-cache <file>", "Save graph to cache file")
19
+ .option("--load-cache <file>", "Load graph from cache file")
20
+ .option("--no-cache", "Disable automatic caching")
21
+ .action(async (options) => {
22
+ // Resolve paths with precedence: -w > -e > --config
23
+ const { workspacePaths, externalPaths } = await resolvePaths(options);
24
+ // Require workspace paths unless loading from cache
25
+ if (workspacePaths.length === 0 && !options.loadCache) {
26
+ console.error("Error: No workspace paths specified. Use -w, --config, or --load-cache.");
27
+ process.exit(1);
28
+ }
29
+ const progress = createProgress("Building workspace graph...");
30
+ progress.start();
31
+ try {
32
+ let graph;
33
+ // Try to load from specified cache file
34
+ if (options.loadCache) {
35
+ const cached = await loadCache(options.loadCache);
36
+ if (cached) {
37
+ graph = OdooGraph.fromBytes(cached);
38
+ progress.text = "Loaded from cache file";
39
+ }
40
+ else {
41
+ throw new Error(`Cache file not found: ${options.loadCache}`);
42
+ }
43
+ }
44
+ else {
45
+ // Try automatic cache
46
+ let cached = null;
47
+ let cacheKey = "";
48
+ if (options.cache !== false) {
49
+ cacheKey = await getCacheKey(workspacePaths, externalPaths);
50
+ cached = await loadCache(cacheKey);
51
+ }
52
+ if (cached) {
53
+ graph = OdooGraph.fromBytes(cached);
54
+ progress.text = "Loaded from cache";
55
+ }
56
+ else {
57
+ // Build new graph
58
+ progress.text = `Building graph (${workspacePaths.length} workspace, ${externalPaths.length} external)...`;
59
+ graph = OdooGraph.build({
60
+ workspace_paths: workspacePaths,
61
+ external_paths: externalPaths,
62
+ });
63
+ // Save to automatic cache
64
+ if (options.cache !== false && cacheKey) {
65
+ await saveCache(cacheKey, graph.serialize());
66
+ }
67
+ }
68
+ }
69
+ // Save to specified cache file if requested
70
+ if (options.saveCache) {
71
+ await saveCache(options.saveCache, graph.serialize());
72
+ progress.text = `Saved to ${options.saveCache}`;
73
+ }
74
+ progress.stop();
75
+ // Output stats
76
+ const stats = graph.stats();
77
+ if (options.format === "json" && !options.gaps) {
78
+ console.log(formatOutput(stats, "json"));
79
+ }
80
+ else if (!options.gaps) {
81
+ console.log(formatStats(stats));
82
+ }
83
+ // Run gap detection if requested
84
+ if (options.gaps) {
85
+ const reports = graph.runGapRules();
86
+ if (options.format === "json") {
87
+ console.log(formatOutput({ stats, gaps: reports }, "json"));
88
+ }
89
+ else {
90
+ console.log(formatStats(stats));
91
+ console.log("\n--- Gap Analysis ---\n");
92
+ for (const report of reports) {
93
+ if (report.diagnostics.length > 0) {
94
+ console.log(formatGapReport(report));
95
+ }
96
+ }
97
+ const total = reports.reduce((sum, r) => sum + r.diagnostics.length, 0);
98
+ if (total > 0) {
99
+ console.log(`\n${total} gap(s) found`);
100
+ process.exitCode = 1;
101
+ }
102
+ else {
103
+ console.log("No gaps found");
104
+ }
105
+ }
106
+ }
107
+ }
108
+ catch (err) {
109
+ progress.stop();
110
+ throw err;
111
+ }
112
+ });
113
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/commands/workspace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Odoo config file parsing
3
+ *
4
+ * Parses odoo.conf to extract addons_path and other settings.
5
+ *
6
+ * Path precedence:
7
+ * 1. -w (workspace) - highest priority
8
+ * 2. -e (external)
9
+ * 3. --config (from odoo.conf) - treated as external, lowest priority
10
+ *
11
+ * Deduplication: Higher priority wins, no duplicates in final lists.
12
+ */
13
+ export interface OdooConfig {
14
+ addons_path: string[];
15
+ db_name?: string;
16
+ db_host?: string;
17
+ }
18
+ /**
19
+ * Parse an Odoo configuration file (INI format)
20
+ */
21
+ export declare function parseOdooConfig(configPath: string): Promise<OdooConfig>;
22
+ export interface ResolvedPaths {
23
+ workspacePaths: string[];
24
+ externalPaths: string[];
25
+ }
26
+ /**
27
+ * Resolve paths with precedence: -w > -e > --config
28
+ *
29
+ * Deduplication ensures no path appears in both lists.
30
+ */
31
+ export declare function resolvePaths(options: {
32
+ workspace?: string[];
33
+ external?: string[];
34
+ config?: string;
35
+ }): Promise<ResolvedPaths>;
36
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAElB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAiD7E;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAC1C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,aAAa,CAAC,CAuCzB"}
package/dist/config.js ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Odoo config file parsing
3
+ *
4
+ * Parses odoo.conf to extract addons_path and other settings.
5
+ *
6
+ * Path precedence:
7
+ * 1. -w (workspace) - highest priority
8
+ * 2. -e (external)
9
+ * 3. --config (from odoo.conf) - treated as external, lowest priority
10
+ *
11
+ * Deduplication: Higher priority wins, no duplicates in final lists.
12
+ */
13
+ import { readFile } from "fs/promises";
14
+ import { resolve, normalize } from "path";
15
+ import { existsSync } from "fs";
16
+ /**
17
+ * Parse an Odoo configuration file (INI format)
18
+ */
19
+ export async function parseOdooConfig(configPath) {
20
+ const fullPath = resolve(configPath);
21
+ const content = await readFile(fullPath, "utf-8");
22
+ const config = {
23
+ addons_path: [],
24
+ };
25
+ // Parse INI format
26
+ const lines = content.split("\n");
27
+ let inOptions = false;
28
+ for (const line of lines) {
29
+ const trimmed = line.trim();
30
+ // Skip comments and empty lines
31
+ if (trimmed.startsWith("#") || trimmed.startsWith(";") || !trimmed) {
32
+ continue;
33
+ }
34
+ // Section header
35
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
36
+ inOptions = trimmed === "[options]";
37
+ continue;
38
+ }
39
+ // Key-value pairs in [options] section
40
+ if (inOptions && trimmed.includes("=")) {
41
+ const [key, ...valueParts] = trimmed.split("=");
42
+ const value = valueParts.join("=").trim();
43
+ if (key.trim() === "addons_path") {
44
+ // Split by comma and resolve paths relative to config file
45
+ const configDir = resolve(fullPath, "..");
46
+ config.addons_path = value
47
+ .split(",")
48
+ .map((p) => p.trim())
49
+ .filter((p) => p.length > 0)
50
+ .map((p) => resolve(configDir, p))
51
+ .map(normalize);
52
+ }
53
+ else if (key.trim() === "db_name") {
54
+ config.db_name = value;
55
+ }
56
+ else if (key.trim() === "db_host") {
57
+ config.db_host = value;
58
+ }
59
+ }
60
+ }
61
+ return config;
62
+ }
63
+ /**
64
+ * Resolve paths with precedence: -w > -e > --config
65
+ *
66
+ * Deduplication ensures no path appears in both lists.
67
+ */
68
+ export async function resolvePaths(options) {
69
+ const seen = new Set();
70
+ const workspacePaths = [];
71
+ const externalPaths = [];
72
+ // 1. Workspace paths (highest priority)
73
+ if (options.workspace) {
74
+ for (const p of options.workspace) {
75
+ const normalized = normalize(resolve(p));
76
+ if (!seen.has(normalized) && existsSync(normalized)) {
77
+ seen.add(normalized);
78
+ workspacePaths.push(normalized);
79
+ }
80
+ }
81
+ }
82
+ // 2. External paths
83
+ if (options.external) {
84
+ for (const p of options.external) {
85
+ const normalized = normalize(resolve(p));
86
+ if (!seen.has(normalized) && existsSync(normalized)) {
87
+ seen.add(normalized);
88
+ externalPaths.push(normalized);
89
+ }
90
+ }
91
+ }
92
+ // 3. Config file paths (lowest priority, treated as external)
93
+ if (options.config) {
94
+ const odooConfig = await parseOdooConfig(options.config);
95
+ for (const p of odooConfig.addons_path) {
96
+ if (!seen.has(p) && existsSync(p)) {
97
+ seen.add(p);
98
+ externalPaths.push(p);
99
+ }
100
+ }
101
+ }
102
+ return { workspacePaths, externalPaths };
103
+ }
104
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for config parsing
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Tests for config parsing
3
+ */
4
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
5
+ import { writeFile, mkdir, rm } from "fs/promises";
6
+ import { join } from "path";
7
+ import { tmpdir } from "os";
8
+ import { parseOdooConfig, resolvePaths } from "./config.js";
9
+ const TEST_DIR = join(tmpdir(), "ograph-test-" + Date.now());
10
+ beforeAll(async () => {
11
+ await mkdir(TEST_DIR, { recursive: true });
12
+ });
13
+ afterAll(async () => {
14
+ await rm(TEST_DIR, { recursive: true, force: true });
15
+ });
16
+ describe("parseOdooConfig", () => {
17
+ it("should parse addons_path from odoo.conf", async () => {
18
+ const configPath = join(TEST_DIR, "odoo.conf");
19
+ await writeFile(configPath, `[options]
20
+ addons_path = /path/to/addons,/path/to/other
21
+ db_name = test_db
22
+ `);
23
+ const config = await parseOdooConfig(configPath);
24
+ expect(config.addons_path).toHaveLength(2);
25
+ expect(config.addons_path[0]).toContain("/path/to/addons");
26
+ expect(config.addons_path[1]).toContain("/path/to/other");
27
+ expect(config.db_name).toBe("test_db");
28
+ });
29
+ it("should handle empty config", async () => {
30
+ const configPath = join(TEST_DIR, "empty.conf");
31
+ await writeFile(configPath, "[options]\n");
32
+ const config = await parseOdooConfig(configPath);
33
+ expect(config.addons_path).toHaveLength(0);
34
+ });
35
+ it("should ignore comments", async () => {
36
+ const configPath = join(TEST_DIR, "comments.conf");
37
+ await writeFile(configPath, `[options]
38
+ # This is a comment
39
+ ; This is also a comment
40
+ addons_path = /real/path
41
+ `);
42
+ const config = await parseOdooConfig(configPath);
43
+ expect(config.addons_path).toHaveLength(1);
44
+ });
45
+ });
46
+ describe("resolvePaths", () => {
47
+ it("should prioritize -w over -e and --config", async () => {
48
+ // Create test directories
49
+ const wsPath = join(TEST_DIR, "workspace");
50
+ const extPath = join(TEST_DIR, "external");
51
+ await mkdir(wsPath, { recursive: true });
52
+ await mkdir(extPath, { recursive: true });
53
+ const result = await resolvePaths({
54
+ workspace: [wsPath],
55
+ external: [extPath, wsPath], // wsPath duplicate should be filtered
56
+ });
57
+ expect(result.workspacePaths).toContain(wsPath);
58
+ expect(result.externalPaths).toContain(extPath);
59
+ expect(result.externalPaths).not.toContain(wsPath); // dedup
60
+ });
61
+ it("should deduplicate paths", async () => {
62
+ const path1 = join(TEST_DIR, "dup1");
63
+ await mkdir(path1, { recursive: true });
64
+ const result = await resolvePaths({
65
+ workspace: [path1, path1], // duplicate
66
+ });
67
+ expect(result.workspacePaths).toHaveLength(1);
68
+ });
69
+ it("should filter non-existent paths", async () => {
70
+ const result = await resolvePaths({
71
+ workspace: ["/nonexistent/path"],
72
+ });
73
+ expect(result.workspacePaths).toHaveLength(0);
74
+ });
75
+ });
76
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Odoo Graph CLI
4
+ *
5
+ * Usage:
6
+ * ograph parse <file> Parse a single file
7
+ * ograph graph <module> Build module graph
8
+ * ograph gaps <path> Detect gaps
9
+ * ograph lint <file|module> Run linting rules
10
+ * ograph workspace Build cross-module graph
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
package/dist/index.js ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Odoo Graph CLI
4
+ *
5
+ * Usage:
6
+ * ograph parse <file> Parse a single file
7
+ * ograph graph <module> Build module graph
8
+ * ograph gaps <path> Detect gaps
9
+ * ograph lint <file|module> Run linting rules
10
+ * ograph workspace Build cross-module graph
11
+ */
12
+ import { Command } from "commander";
13
+ import { init } from "@odoograph/wasm";
14
+ // Import commands
15
+ import { parseCommand } from "./commands/parse.js";
16
+ import { lintCommand } from "./commands/lint.js";
17
+ import { gapsCommand } from "./commands/gaps.js";
18
+ import { graphCommand } from "./commands/graph.js";
19
+ import { workspaceCommand } from "./commands/workspace.js";
20
+ const program = new Command();
21
+ program
22
+ .name("ograph")
23
+ .description("Cross-file semantic analysis for Odoo modules")
24
+ .version("0.1.0");
25
+ // Register commands
26
+ program.addCommand(parseCommand);
27
+ program.addCommand(lintCommand);
28
+ program.addCommand(gapsCommand);
29
+ program.addCommand(graphCommand);
30
+ program.addCommand(workspaceCommand);
31
+ // Main entry
32
+ async function main() {
33
+ // Initialize WASM module
34
+ await init();
35
+ // Parse arguments
36
+ await program.parseAsync(process.argv);
37
+ }
38
+ main().catch((err) => {
39
+ console.error("Error:", err.message);
40
+ process.exit(1);
41
+ });
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,kBAAkB;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,+CAA+C,CAAC;KAC5D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AAErC,aAAa;AACb,KAAK,UAAU,IAAI;IACjB,yBAAyB;IACzB,MAAM,IAAI,EAAE,CAAC;IAEb,kBAAkB;IAClB,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Output formatting utilities
3
+ *
4
+ * Supports JSON and human-readable output formats.
5
+ */
6
+ import type { Diagnostic, GapReport, GraphStats } from "@odoograph/wasm";
7
+ /**
8
+ * Format any data as JSON or human-readable
9
+ */
10
+ export declare function formatOutput(data: unknown, format: string): string;
11
+ /**
12
+ * Format a single diagnostic
13
+ */
14
+ export declare function formatDiagnostic(d: Diagnostic): string;
15
+ /**
16
+ * Format diagnostics for a file
17
+ */
18
+ export declare function formatDiagnostics(file: string, diagnostics: Diagnostic[]): string;
19
+ /**
20
+ * Format gap report for a module
21
+ */
22
+ export declare function formatGapReport(report: GapReport): string;
23
+ /**
24
+ * Format graph statistics
25
+ */
26
+ export declare function formatStats(stats: GraphStats): string;
27
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAY,MAAM,iBAAiB,CAAC;AAEnF;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOlE;AA4BD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAMtD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAYjF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAoCzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CASrD"}
package/dist/output.js ADDED
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Output formatting utilities
3
+ *
4
+ * Supports JSON and human-readable output formats.
5
+ */
6
+ import chalk from "chalk";
7
+ /**
8
+ * Format any data as JSON or human-readable
9
+ */
10
+ export function formatOutput(data, format) {
11
+ if (format === "json") {
12
+ return JSON.stringify(data, null, 2);
13
+ }
14
+ // Default to human-readable (handled by specific formatters)
15
+ return JSON.stringify(data, null, 2);
16
+ }
17
+ /**
18
+ * Get color for severity level
19
+ */
20
+ function severityColor(severity) {
21
+ switch (severity) {
22
+ case "critical":
23
+ return chalk.bgRed.white;
24
+ case "error":
25
+ return chalk.red;
26
+ case "warning":
27
+ return chalk.yellow;
28
+ case "info":
29
+ return chalk.blue;
30
+ default:
31
+ return chalk.white;
32
+ }
33
+ }
34
+ /**
35
+ * Format severity badge
36
+ */
37
+ function severityBadge(severity) {
38
+ const color = severityColor(severity);
39
+ return color(` ${severity.toUpperCase()} `);
40
+ }
41
+ /**
42
+ * Format a single diagnostic
43
+ */
44
+ export function formatDiagnostic(d) {
45
+ const location = d.line ? `:${d.line}${d.column ? `:${d.column}` : ""}` : "";
46
+ const badge = severityBadge(d.severity);
47
+ const ruleId = chalk.dim(`[${d.rule_id}]`);
48
+ return ` ${badge} ${ruleId} ${d.message}${location ? chalk.dim(location) : ""}`;
49
+ }
50
+ /**
51
+ * Format diagnostics for a file
52
+ */
53
+ export function formatDiagnostics(file, diagnostics) {
54
+ if (diagnostics.length === 0) {
55
+ return "";
56
+ }
57
+ const lines = [chalk.underline(file)];
58
+ for (const d of diagnostics) {
59
+ lines.push(formatDiagnostic(d));
60
+ }
61
+ return lines.join("\n");
62
+ }
63
+ /**
64
+ * Format gap report for a module
65
+ */
66
+ export function formatGapReport(report) {
67
+ if (report.diagnostics.length === 0) {
68
+ return "";
69
+ }
70
+ const lines = [chalk.bold.cyan(`📦 ${report.module}`)];
71
+ // Group by severity
72
+ const bySeverity = new Map();
73
+ for (const d of report.diagnostics) {
74
+ const list = bySeverity.get(d.severity) || [];
75
+ list.push(d);
76
+ bySeverity.set(d.severity, list);
77
+ }
78
+ // Output in severity order
79
+ for (const severity of ["critical", "error", "warning", "info"]) {
80
+ const items = bySeverity.get(severity) || [];
81
+ for (const d of items) {
82
+ lines.push(formatDiagnostic(d));
83
+ }
84
+ }
85
+ // Summary line
86
+ const { critical, error, warning, info } = report.summary;
87
+ const parts = [];
88
+ if (critical > 0)
89
+ parts.push(chalk.bgRed.white(` ${critical} critical `));
90
+ if (error > 0)
91
+ parts.push(chalk.red(`${error} errors`));
92
+ if (warning > 0)
93
+ parts.push(chalk.yellow(`${warning} warnings`));
94
+ if (info > 0)
95
+ parts.push(chalk.blue(`${info} info`));
96
+ if (parts.length > 0) {
97
+ lines.push(` ${parts.join(" • ")}`);
98
+ }
99
+ return lines.join("\n");
100
+ }
101
+ /**
102
+ * Format graph statistics
103
+ */
104
+ export function formatStats(stats) {
105
+ return [
106
+ chalk.bold("Graph Statistics"),
107
+ ` Modules: ${stats.modules} (${stats.workspace_modules} workspace, ${stats.external_modules} external)`,
108
+ ` Models: ${stats.models}`,
109
+ ` Views: ${stats.views}`,
110
+ ` Files: ${stats.files_parsed}`,
111
+ ` Duration: ${stats.duration_ms}ms`,
112
+ ].join("\n");
113
+ }
114
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Terminal progress display
3
+ *
4
+ * Provides spinner and progress bar for long-running operations.
5
+ */
6
+ import type { Progress } from "@odoograph/wasm";
7
+ /**
8
+ * Simple progress wrapper around ora spinner
9
+ */
10
+ export interface ProgressDisplay {
11
+ start(): void;
12
+ stop(): void;
13
+ succeed(text?: string): void;
14
+ fail(text?: string): void;
15
+ text: string;
16
+ }
17
+ /**
18
+ * Create a progress spinner
19
+ */
20
+ export declare function createProgress(initialText: string): ProgressDisplay;
21
+ /**
22
+ * Format progress update for display
23
+ */
24
+ export declare function formatProgress(progress: Progress): string;
25
+ /**
26
+ * Create a progress handler that updates a spinner
27
+ */
28
+ export declare function createProgressHandler(spinner: ProgressDisplay): (progress: Progress) => void;
29
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;IACb,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CA0BnE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAsBzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,GACvB,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAI9B"}