@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.
- package/README.md +118 -0
- package/dist/cache.d.ts +35 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +108 -0
- package/dist/cache.js.map +1 -0
- package/dist/cache.test.d.ts +5 -0
- package/dist/cache.test.d.ts.map +1 -0
- package/dist/cache.test.js +54 -0
- package/dist/cache.test.js.map +1 -0
- package/dist/commands/gaps.d.ts +6 -0
- package/dist/commands/gaps.d.ts.map +1 -0
- package/dist/commands/gaps.js +87 -0
- package/dist/commands/gaps.js.map +1 -0
- package/dist/commands/graph.d.ts +6 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/graph.js +36 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/lint.d.ts +6 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +56 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/parse.d.ts +6 -0
- package/dist/commands/parse.d.ts.map +1 -0
- package/dist/commands/parse.js +60 -0
- package/dist/commands/parse.js.map +1 -0
- package/dist/commands/workspace.d.ts +6 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +113 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +104 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +5 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +76 -0
- package/dist/config.test.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +27 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +114 -0
- package/dist/output.js.map +1 -0
- package/dist/progress.d.ts +29 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +65 -0
- package/dist/progress.js.map +1 -0
- package/dist/utils.d.ts +24 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +104 -0
- package/dist/utils.js.map +1 -0
- package/package.json +53 -0
|
@@ -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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"}
|
package/dist/config.d.ts
ADDED
|
@@ -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 @@
|
|
|
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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/output.d.ts
ADDED
|
@@ -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"}
|