@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
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # @odoograph/cli
2
+
3
+ Cross-file semantic analysis CLI for Odoo modules.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @odoograph/cli
9
+ ```
10
+
11
+ Or run directly with npx:
12
+
13
+ ```bash
14
+ npx @odoograph/cli --help
15
+ ```
16
+
17
+ ## Commands
18
+
19
+ ### `ograph parse <file>`
20
+
21
+ Parse a single file into structured JSON.
22
+
23
+ ```bash
24
+ ograph parse models/sale.py
25
+ ograph parse views/sale_views.xml --format human
26
+ ```
27
+
28
+ ### `ograph lint <path>`
29
+
30
+ Run linting rules on a file or module.
31
+
32
+ ```bash
33
+ ograph lint models/sale.py
34
+ ograph lint ./my_module
35
+ ograph lint ./my_module --format json
36
+ ```
37
+
38
+ ### `ograph gaps <path>`
39
+
40
+ Run gap detection rules on a module.
41
+
42
+ ```bash
43
+ ograph gaps ./my_module
44
+ ograph gaps ./my_module --category G1xx # Filter by category
45
+ ograph gaps ./my_module --severity error # Filter by severity
46
+ ```
47
+
48
+ ### `ograph graph <module>`
49
+
50
+ Build and display module graph statistics.
51
+
52
+ ```bash
53
+ ograph graph ./my_module
54
+ ograph graph ./my_module --format json
55
+ ```
56
+
57
+ ### `ograph workspace`
58
+
59
+ Build cross-module workspace graph with full analysis.
60
+
61
+ ```bash
62
+ # Basic usage with explicit paths
63
+ ograph workspace -w ./addons -e /path/to/odoo/addons
64
+
65
+ # Using Odoo config file
66
+ ograph workspace -w ./addons --config ~/.odoorc
67
+
68
+ # Run gap detection
69
+ ograph workspace -w ./addons --config ~/.odoorc --gaps
70
+
71
+ # Cache the graph for reuse
72
+ ograph workspace -w ./addons --save-cache ./graph.bin
73
+ ograph workspace --load-cache ./graph.bin --gaps
74
+ ```
75
+
76
+ **Path Resolution & Precedence:**
77
+
78
+ ```
79
+ Priority: -w > -e > --config
80
+
81
+ 1. Paths from -w → workspace (highest priority)
82
+ 2. Paths from -e → external
83
+ 3. Paths from --config → external (lowest priority)
84
+
85
+ Deduplication: If a path appears in multiple sources,
86
+ higher priority wins. No duplicates in final graph.
87
+ ```
88
+
89
+ ## Options
90
+
91
+ | Option | Description |
92
+ |--------|-------------|
93
+ | `-w, --workspace <paths...>` | Workspace addon paths (analyzed for issues) |
94
+ | `-e, --external <paths...>` | External addon paths (for dependency resolution) |
95
+ | `-c, --config <file>` | Odoo config file to read `addons_path` |
96
+ | `-f, --format <format>` | Output format: `json` or `human` |
97
+ | `--gaps` | Run gap detection after building graph |
98
+ | `--save-cache <file>` | Save graph to cache file |
99
+ | `--load-cache <file>` | Load graph from cache file |
100
+ | `--no-cache` | Disable automatic caching |
101
+
102
+ ## Requirements
103
+
104
+ - Node.js >= 20.0.0
105
+
106
+ ## License
107
+
108
+ Copyright © 2025 Solutions Unity Co. See [LICENSE](./LICENSE) for details.
109
+
110
+ ---
111
+
112
+ **OdooGraph** is developed and maintained by [Hussain Hammad](https://github.com/hussain) and [Solutions Unity Co.](https://solutionsunity.com)
113
+
114
+ This repository distributes compiled artifacts only.
115
+ The core analysis engine is proprietary.
116
+
117
+ For more information, visit [odoograph.com](https://odoograph.com)
118
+
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Disk cache for graph persistence
3
+ *
4
+ * Cache location: ~/.odoo-graph/cache/
5
+ * Key format: hash of workspace paths + file mtimes
6
+ */
7
+ /**
8
+ * Get cache key from paths (hash of sorted paths)
9
+ */
10
+ export declare function getCacheKey(workspacePaths: string[], externalPaths: string[]): Promise<string>;
11
+ /**
12
+ * Load cached graph from disk
13
+ *
14
+ * @param keyOrPath - Cache key (for automatic cache) or absolute path (for --load-cache)
15
+ */
16
+ export declare function loadCache(keyOrPath: string): Promise<Uint8Array | null>;
17
+ /**
18
+ * Save graph to cache
19
+ *
20
+ * @param keyOrPath - Cache key (for automatic cache) or absolute path (for --save-cache)
21
+ * @param data - Serialized graph data
22
+ */
23
+ export declare function saveCache(keyOrPath: string, data: Uint8Array): Promise<void>;
24
+ /**
25
+ * Clear cache directory
26
+ */
27
+ export declare function clearCache(): Promise<number>;
28
+ /**
29
+ * Get cache statistics
30
+ */
31
+ export declare function getCacheStats(): Promise<{
32
+ entries: number;
33
+ totalSize: number;
34
+ }>;
35
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH;;GAEG;AACH,wBAAsB,WAAW,CAC/B,cAAc,EAAE,MAAM,EAAE,EACxB,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAgB7E;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAiBlD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAkBD"}
package/dist/cache.js ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Disk cache for graph persistence
3
+ *
4
+ * Cache location: ~/.odoo-graph/cache/
5
+ * Key format: hash of workspace paths + file mtimes
6
+ */
7
+ import { readFile, writeFile, mkdir, stat, readdir } from "fs/promises";
8
+ import { join } from "path";
9
+ import { homedir } from "os";
10
+ import { createHash } from "crypto";
11
+ import { existsSync } from "fs";
12
+ const CACHE_VERSION = "1";
13
+ const CACHE_DIR = join(homedir(), ".odoo-graph", "cache");
14
+ /**
15
+ * Get cache key from paths (hash of sorted paths)
16
+ */
17
+ export async function getCacheKey(workspacePaths, externalPaths) {
18
+ const allPaths = [...workspacePaths, ...externalPaths].sort();
19
+ const hash = createHash("sha256");
20
+ hash.update(CACHE_VERSION);
21
+ for (const p of allPaths) {
22
+ hash.update(p);
23
+ // Include mtime of path for invalidation
24
+ try {
25
+ const s = await stat(p);
26
+ hash.update(s.mtimeMs.toString());
27
+ }
28
+ catch {
29
+ // Path doesn't exist or can't be accessed
30
+ hash.update("missing");
31
+ }
32
+ }
33
+ return hash.digest("hex").substring(0, 16);
34
+ }
35
+ /**
36
+ * Load cached graph from disk
37
+ *
38
+ * @param keyOrPath - Cache key (for automatic cache) or absolute path (for --load-cache)
39
+ */
40
+ export async function loadCache(keyOrPath) {
41
+ try {
42
+ // If it's an absolute path, load directly
43
+ const cachePath = keyOrPath.startsWith("/")
44
+ ? keyOrPath
45
+ : join(CACHE_DIR, `${keyOrPath}.bin`);
46
+ if (!existsSync(cachePath)) {
47
+ return null;
48
+ }
49
+ const buffer = await readFile(cachePath);
50
+ return new Uint8Array(buffer);
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ /**
57
+ * Save graph to cache
58
+ *
59
+ * @param keyOrPath - Cache key (for automatic cache) or absolute path (for --save-cache)
60
+ * @param data - Serialized graph data
61
+ */
62
+ export async function saveCache(keyOrPath, data) {
63
+ // Determine target path
64
+ const isAbsolute = keyOrPath.startsWith("/");
65
+ const cachePath = isAbsolute ? keyOrPath : join(CACHE_DIR, `${keyOrPath}.bin`);
66
+ // Ensure directory exists
67
+ const dir = isAbsolute ? join(cachePath, "..") : CACHE_DIR;
68
+ await mkdir(dir, { recursive: true });
69
+ await writeFile(cachePath, data);
70
+ }
71
+ /**
72
+ * Clear cache directory
73
+ */
74
+ export async function clearCache() {
75
+ if (!existsSync(CACHE_DIR)) {
76
+ return 0;
77
+ }
78
+ const files = await readdir(CACHE_DIR);
79
+ let count = 0;
80
+ for (const file of files) {
81
+ if (file.endsWith(".bin")) {
82
+ const { unlink } = await import("fs/promises");
83
+ await unlink(join(CACHE_DIR, file));
84
+ count++;
85
+ }
86
+ }
87
+ return count;
88
+ }
89
+ /**
90
+ * Get cache statistics
91
+ */
92
+ export async function getCacheStats() {
93
+ if (!existsSync(CACHE_DIR)) {
94
+ return { entries: 0, totalSize: 0 };
95
+ }
96
+ const files = await readdir(CACHE_DIR);
97
+ let entries = 0;
98
+ let totalSize = 0;
99
+ for (const file of files) {
100
+ if (file.endsWith(".bin")) {
101
+ const s = await stat(join(CACHE_DIR, file));
102
+ entries++;
103
+ totalSize += s.size;
104
+ }
105
+ }
106
+ return { entries, totalSize };
107
+ }
108
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for cache functionality
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../src/cache.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Tests for cache functionality
3
+ */
4
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
5
+ import { mkdir, rm } from "fs/promises";
6
+ import { join } from "path";
7
+ import { tmpdir } from "os";
8
+ import { getCacheKey, loadCache, saveCache } from "./cache.js";
9
+ const TEST_DIR = join(tmpdir(), "ograph-cache-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("getCacheKey", () => {
17
+ it("should generate consistent keys for same paths", async () => {
18
+ const paths = ["/path/a", "/path/b"];
19
+ const key1 = await getCacheKey(paths, []);
20
+ const key2 = await getCacheKey(paths, []);
21
+ expect(key1).toBe(key2);
22
+ });
23
+ it("should generate different keys for different paths", async () => {
24
+ const key1 = await getCacheKey(["/path/a"], []);
25
+ const key2 = await getCacheKey(["/path/b"], []);
26
+ expect(key1).not.toBe(key2);
27
+ });
28
+ it("should include external paths in key", async () => {
29
+ const key1 = await getCacheKey(["/path/a"], []);
30
+ const key2 = await getCacheKey(["/path/a"], ["/path/ext"]);
31
+ expect(key1).not.toBe(key2);
32
+ });
33
+ });
34
+ describe("saveCache and loadCache", () => {
35
+ it("should save and load cache from absolute path", async () => {
36
+ const cachePath = join(TEST_DIR, "test.bin");
37
+ const data = new Uint8Array([1, 2, 3, 4, 5]);
38
+ await saveCache(cachePath, data);
39
+ const loaded = await loadCache(cachePath);
40
+ expect(loaded).toEqual(data);
41
+ });
42
+ it("should return null for non-existent cache", async () => {
43
+ const loaded = await loadCache(join(TEST_DIR, "nonexistent.bin"));
44
+ expect(loaded).toBeNull();
45
+ });
46
+ it("should handle empty data", async () => {
47
+ const cachePath = join(TEST_DIR, "empty.bin");
48
+ const data = new Uint8Array([]);
49
+ await saveCache(cachePath, data);
50
+ const loaded = await loadCache(cachePath);
51
+ expect(loaded).toEqual(data);
52
+ });
53
+ });
54
+ //# sourceMappingURL=cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../src/cache.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Gaps command - run gap detection rules on a module or workspace
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const gapsCommand: Command;
6
+ //# sourceMappingURL=gaps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gaps.d.ts","sourceRoot":"","sources":["../../src/commands/gaps.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,WAAW,SAgGrB,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Gaps command - run gap detection rules on a module or workspace
3
+ */
4
+ import { Command } from "commander";
5
+ import { resolve } from "path";
6
+ import { OdooGraph } from "@odoograph/wasm";
7
+ import { formatOutput, formatGapReport } from "../output.js";
8
+ import { loadCache, saveCache, getCacheKey } from "../cache.js";
9
+ import { createProgress } from "../progress.js";
10
+ export const gapsCommand = new Command("gaps")
11
+ .description("Run gap detection rules on a module")
12
+ .argument("<path>", "Module path to analyze")
13
+ .option("-f, --format <format>", "Output format: json, human", "human")
14
+ .option("-c, --category <cat>", "Filter by category (e.g., G1xx, G2xx)")
15
+ .option("-s, --severity <sev>", "Filter by severity (critical, error, warning, info)")
16
+ .option("--no-cache", "Disable cache")
17
+ .action(async (targetPath, options) => {
18
+ const modulePath = resolve(targetPath);
19
+ const progress = createProgress("Analyzing gaps...");
20
+ progress.start();
21
+ try {
22
+ // Try to load from cache first
23
+ let graph = null;
24
+ if (options.cache) {
25
+ const cacheKey = await getCacheKey([modulePath], []);
26
+ const cached = await loadCache(cacheKey);
27
+ if (cached) {
28
+ graph = OdooGraph.fromBytes(cached);
29
+ progress.text = "Loaded from cache";
30
+ }
31
+ }
32
+ // Build graph if not cached
33
+ if (!graph) {
34
+ progress.text = "Building graph...";
35
+ graph = OdooGraph.build({
36
+ workspace_paths: [modulePath],
37
+ external_paths: [],
38
+ });
39
+ // Save to cache
40
+ if (options.cache) {
41
+ const cacheKey = await getCacheKey([modulePath], []);
42
+ await saveCache(cacheKey, graph.serialize());
43
+ }
44
+ }
45
+ progress.text = "Running gap rules...";
46
+ let reports = graph.runGapRules();
47
+ // Apply filters
48
+ if (options.category || options.severity) {
49
+ reports = reports.map((report) => ({
50
+ ...report,
51
+ diagnostics: report.diagnostics.filter((d) => {
52
+ if (options.category && !d.rule_id.startsWith(options.category)) {
53
+ return false;
54
+ }
55
+ if (options.severity && d.severity !== options.severity) {
56
+ return false;
57
+ }
58
+ return true;
59
+ }),
60
+ }));
61
+ }
62
+ progress.stop();
63
+ // Output
64
+ if (options.format === "json") {
65
+ console.log(formatOutput(reports, "json"));
66
+ }
67
+ else {
68
+ for (const report of reports) {
69
+ console.log(formatGapReport(report));
70
+ }
71
+ // Summary
72
+ const total = reports.reduce((sum, r) => sum + r.diagnostics.length, 0);
73
+ if (total > 0) {
74
+ console.log(`\n${total} gap(s) found`);
75
+ process.exitCode = 1;
76
+ }
77
+ else {
78
+ console.log("No gaps found");
79
+ }
80
+ }
81
+ }
82
+ catch (err) {
83
+ progress.stop();
84
+ throw err;
85
+ }
86
+ });
87
+ //# sourceMappingURL=gaps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gaps.js","sourceRoot":"","sources":["../../src/commands/gaps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Graph command - build and display module graph
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const graphCommand: Command;
6
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/commands/graph.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,YAAY,SA6BrB,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Graph command - build and display module graph
3
+ */
4
+ import { Command } from "commander";
5
+ import { resolve } from "path";
6
+ import { OdooGraph } from "@odoograph/wasm";
7
+ import { formatOutput, formatStats } from "../output.js";
8
+ import { createProgress } from "../progress.js";
9
+ export const graphCommand = new Command("graph")
10
+ .description("Build and display module graph")
11
+ .argument("<module>", "Module path to analyze")
12
+ .option("-f, --format <format>", "Output format: json, human", "human")
13
+ .action(async (modulePath, options) => {
14
+ const fullPath = resolve(modulePath);
15
+ const progress = createProgress("Building graph...");
16
+ progress.start();
17
+ try {
18
+ const graph = OdooGraph.build({
19
+ workspace_paths: [fullPath],
20
+ external_paths: [],
21
+ });
22
+ progress.stop();
23
+ const stats = graph.stats();
24
+ if (options.format === "json") {
25
+ console.log(formatOutput(stats, "json"));
26
+ }
27
+ else {
28
+ console.log(formatStats(stats));
29
+ }
30
+ }
31
+ catch (err) {
32
+ progress.stop();
33
+ throw err;
34
+ }
35
+ });
36
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/commands/graph.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,gCAAgC,CAAC;KAC7C,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;KAC9C,MAAM,CAAC,uBAAuB,EAAE,4BAA4B,EAAE,OAAO,CAAC;KACtE,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,OAA2B,EAAE,EAAE;IAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,cAAc,CAAC,mBAAmB,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,CAAC;IAEjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;YAC5B,eAAe,EAAE,CAAC,QAAQ,CAAC;YAC3B,cAAc,EAAE,EAAE;SACnB,CAAC,CAAC;QAEH,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEhB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAE5B,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Lint command - run linting rules on files or modules
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const lintCommand: Command;
6
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,WAAW,SAwDrB,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Lint command - run linting rules on files or modules
3
+ */
4
+ import { Command } from "commander";
5
+ import { readFile, stat } from "fs/promises";
6
+ import { resolve, relative } from "path";
7
+ import { lintFile } from "@odoograph/wasm";
8
+ import { formatOutput, formatDiagnostics } from "../output.js";
9
+ import { walkOdooFiles } from "../utils.js";
10
+ export const lintCommand = new Command("lint")
11
+ .description("Run linting rules on a file or module")
12
+ .argument("<path>", "File or module directory to lint")
13
+ .option("-f, --format <format>", "Output format: json, human", "human")
14
+ .option("--fix", "Apply automatic fixes (where available)", false)
15
+ .action(async (targetPath, options) => {
16
+ const fullPath = resolve(targetPath);
17
+ const pathStat = await stat(fullPath);
18
+ let allDiagnostics = [];
19
+ if (pathStat.isFile()) {
20
+ // Lint single file
21
+ const content = await readFile(fullPath, "utf-8");
22
+ const diagnostics = lintFile(content, fullPath);
23
+ allDiagnostics.push({ file: fullPath, diagnostics });
24
+ }
25
+ else if (pathStat.isDirectory()) {
26
+ // Lint all files in module
27
+ const files = await walkOdooFiles(fullPath);
28
+ for (const file of files) {
29
+ const content = await readFile(file, "utf-8");
30
+ const diagnostics = lintFile(content, file);
31
+ if (diagnostics.length > 0) {
32
+ allDiagnostics.push({ file, diagnostics });
33
+ }
34
+ }
35
+ }
36
+ if (options.format === "json") {
37
+ console.log(formatOutput(allDiagnostics, "json"));
38
+ }
39
+ else {
40
+ const cwd = process.cwd();
41
+ for (const { file, diagnostics } of allDiagnostics) {
42
+ const relPath = relative(cwd, file);
43
+ console.log(formatDiagnostics(relPath, diagnostics));
44
+ }
45
+ // Summary
46
+ const total = allDiagnostics.reduce((sum, f) => sum + f.diagnostics.length, 0);
47
+ if (total > 0) {
48
+ console.log(`\n${total} issue(s) found`);
49
+ process.exitCode = 1;
50
+ }
51
+ else {
52
+ console.log("No issues found");
53
+ }
54
+ }
55
+ });
56
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAmB,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,uCAAuC,CAAC;KACpD,QAAQ,CAAC,QAAQ,EAAE,kCAAkC,CAAC;KACtD,MAAM,CAAC,uBAAuB,EAAE,4BAA4B,EAAE,OAAO,CAAC;KACtE,MAAM,CAAC,OAAO,EAAE,yCAAyC,EAAE,KAAK,CAAC;KACjE,MAAM,CACL,KAAK,EACH,UAAkB,EAClB,OAAyC,EACzC,EAAE;IACF,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEtC,IAAI,cAAc,GAChB,EAAE,CAAC;IAEL,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACtB,mBAAmB;QACnB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAChD,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;IACvD,CAAC;SAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAClC,2BAA2B;QAC3B,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;QAE5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC5C,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,KAAK,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,cAAc,EAAE,CAAC;YACnD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,UAAU;QACV,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CACjC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,EACtC,CAAC,CACF,CAAC;QACF,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,iBAAiB,CAAC,CAAC;YACzC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;AACH,CAAC,CACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Parse command - parse a single file and output structured data
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const parseCommand: Command;
6
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/commands/parse.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,YAAY,SA2DrB,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Parse command - parse a single file and output structured data
3
+ */
4
+ import { Command } from "commander";
5
+ import { readFile } from "fs/promises";
6
+ import { resolve } from "path";
7
+ import { formatOutput } from "../output.js";
8
+ export const parseCommand = new Command("parse")
9
+ .description("Parse a single file into structured JSON")
10
+ .argument("<file>", "File to parse")
11
+ .option("-f, --format <format>", "Output format: json, human", "json")
12
+ .action(async (file, options) => {
13
+ const filePath = resolve(file);
14
+ const content = await readFile(filePath, "utf-8");
15
+ // Determine file type and parse
16
+ const ext = filePath.split(".").pop()?.toLowerCase();
17
+ let result;
18
+ switch (ext) {
19
+ case "py":
20
+ // For now, we'll use a simple parse result
21
+ // In Phase 2, this would use web-tree-sitter
22
+ result = {
23
+ type: "python",
24
+ path: filePath,
25
+ size: content.length,
26
+ lines: content.split("\n").length,
27
+ // TODO: Add actual parsing with WASM
28
+ };
29
+ break;
30
+ case "xml":
31
+ result = {
32
+ type: "xml",
33
+ path: filePath,
34
+ size: content.length,
35
+ lines: content.split("\n").length,
36
+ // TODO: Add actual parsing with WASM
37
+ };
38
+ break;
39
+ case "csv":
40
+ result = {
41
+ type: "csv",
42
+ path: filePath,
43
+ size: content.length,
44
+ lines: content.split("\n").length,
45
+ };
46
+ break;
47
+ case "js":
48
+ result = {
49
+ type: "javascript",
50
+ path: filePath,
51
+ size: content.length,
52
+ lines: content.split("\n").length,
53
+ };
54
+ break;
55
+ default:
56
+ throw new Error(`Unsupported file type: ${ext}`);
57
+ }
58
+ console.log(formatOutput(result, options.format));
59
+ });
60
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/commands/parse.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,0CAA0C,CAAC;KACvD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;KACnC,MAAM,CAAC,uBAAuB,EAAE,4BAA4B,EAAE,MAAM,CAAC;KACrE,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,OAA2B,EAAE,EAAE;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElD,gCAAgC;IAChC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;IAErD,IAAI,MAAc,CAAC;IAEnB,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,IAAI;YACP,2CAA2C;YAC3C,6CAA6C;YAC7C,MAAM,GAAG;gBACP,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,OAAO,CAAC,MAAM;gBACpB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;gBACjC,qCAAqC;aACtC,CAAC;YACF,MAAM;QAER,KAAK,KAAK;YACR,MAAM,GAAG;gBACP,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,OAAO,CAAC,MAAM;gBACpB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;gBACjC,qCAAqC;aACtC,CAAC;YACF,MAAM;QAER,KAAK,KAAK;YACR,MAAM,GAAG;gBACP,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,OAAO,CAAC,MAAM;gBACpB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;aAClC,CAAC;YACF,MAAM;QAER,KAAK,IAAI;YACP,MAAM,GAAG;gBACP,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,OAAO,CAAC,MAAM;gBACpB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;aAClC,CAAC;YACF,MAAM;QAER;YACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC"}