@cesarandreslopez/occ 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -47
- package/dist/src/code/check.d.ts +39 -0
- package/dist/src/code/check.js +242 -0
- package/dist/src/code/check.js.map +1 -0
- package/dist/src/code/command.js +64 -0
- package/dist/src/code/command.js.map +1 -1
- package/dist/src/code/isolated-chunk-runner.d.ts +5 -0
- package/dist/src/code/isolated-chunk-runner.js +96 -0
- package/dist/src/code/isolated-chunk-runner.js.map +1 -0
- package/dist/src/code/isolated.d.ts +30 -2
- package/dist/src/code/isolated.js +110 -2
- package/dist/src/code/isolated.js.map +1 -1
- package/dist/src/code/languages.d.ts +13 -0
- package/dist/src/code/languages.js +115 -2
- package/dist/src/code/languages.js.map +1 -1
- package/dist/src/code/map.d.ts +9 -0
- package/dist/src/code/map.js +6 -0
- package/dist/src/code/map.js.map +1 -1
- package/dist/src/code/parsers.js +262 -0
- package/dist/src/code/parsers.js.map +1 -1
- package/dist/src/code/session.d.ts +2 -0
- package/dist/src/code/session.js +4 -0
- package/dist/src/code/session.js.map +1 -1
- package/dist/src/code/source.d.ts +44 -0
- package/dist/src/code/source.js +102 -0
- package/dist/src/code/source.js.map +1 -0
- package/dist/src/code/store.d.ts +10 -0
- package/dist/src/code/store.js +11 -0
- package/dist/src/code/store.js.map +1 -1
- package/dist/src/code/tree-sitter.d.ts +20 -0
- package/dist/src/code/tree-sitter.js +127 -0
- package/dist/src/code/tree-sitter.js.map +1 -0
- package/dist/src/index.d.ts +11 -4
- package/dist/src/index.js +7 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/progress-event.d.ts +8 -0
- package/dist/src/workspace/bundle-io.d.ts +9 -1
- package/dist/src/workspace/bundle-io.js +59 -18
- package/dist/src/workspace/bundle-io.js.map +1 -1
- package/dist/src/workspace/bundle.js +55 -1
- package/dist/src/workspace/bundle.js.map +1 -1
- package/package.json +18 -2
- package/skills/occ/SKILL.md +16 -5
- package/skills/occ/reference/code.md +35 -2
- package/skills/occ/reference/commands.md +3 -1
- package/vendor/tree-sitter/c/grammar.wasm +0 -0
- package/vendor/tree-sitter/c/tags.scm +4 -0
- package/vendor/tree-sitter/c-sharp/grammar.wasm +0 -0
- package/vendor/tree-sitter/c-sharp/tags.scm +6 -0
- package/vendor/tree-sitter/cpp/grammar.wasm +0 -0
- package/vendor/tree-sitter/cpp/tags.scm +5 -0
- package/vendor/tree-sitter/go/grammar.wasm +0 -0
- package/vendor/tree-sitter/go/tags.scm +4 -0
- package/vendor/tree-sitter/java/grammar.wasm +0 -0
- package/vendor/tree-sitter/java/tags.scm +7 -0
- package/vendor/tree-sitter/kotlin/grammar.wasm +0 -0
- package/vendor/tree-sitter/kotlin/tags.scm +4 -0
- package/vendor/tree-sitter/php/grammar.wasm +0 -0
- package/vendor/tree-sitter/php/tags.scm +8 -0
- package/vendor/tree-sitter/python/grammar.wasm +0 -0
- package/vendor/tree-sitter/python/tags.scm +3 -0
- package/vendor/tree-sitter/ruby/grammar.wasm +0 -0
- package/vendor/tree-sitter/ruby/tags.scm +5 -0
- package/vendor/tree-sitter/rust/grammar.wasm +0 -0
- package/vendor/tree-sitter/rust/tags.scm +5 -0
- package/vendor/tree-sitter/scala/grammar.wasm +0 -0
- package/vendor/tree-sitter/scala/tags.scm +5 -0
- package/vendor/tree-sitter/swift/grammar.wasm +0 -0
- package/vendor/tree-sitter/swift/tags.scm +4 -0
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ OCC started as a way to make office documents visible in the same workflows that
|
|
|
25
25
|
- analyze workspaces for combined code, document, and structure metrics (`occ workspace analyze`) and cross-document references (`occ workspace documents`)
|
|
26
26
|
- quickly describe whether a directory is a code, office, documentation, data, or mixed project (`occ describe`, `occ workspace describe`)
|
|
27
27
|
- summarize code metrics through `scc`
|
|
28
|
-
- explore JavaScript, TypeScript, Vue Single-File Components, and
|
|
28
|
+
- explore JavaScript, TypeScript, Vue Single-File Components, Python, Go, Rust, Java, C/C++, Kotlin, and other tree-sitter-backed repositories with symbol search, exact `nodeId` source reads, syntax checks, call analysis, dependency inspection, and inheritance queries (`occ code`)
|
|
29
29
|
- track git changes, diffs, commit history, and churn — and map a diff to the code symbols it touches (`occ git`, `occ code diff`, `occ code history`)
|
|
30
30
|
|
|
31
31
|
## Agent Skills
|
|
@@ -69,7 +69,7 @@ After install the skill lands at `<skills-dir>/occ/SKILL.md` and your agent surf
|
|
|
69
69
|
- **Presentation inspection via `occ slide inspect`** — metadata, risk flags, per-slide inventory, and content preview for PPTX and ODP
|
|
70
70
|
- **Table extraction via `occ table inspect`** — structured table content from DOCX, XLSX, PPTX, ODT, and ODP with auto-detected headers, sample row limits, and merged cell support
|
|
71
71
|
- **Code metrics via scc** — auto-detects code files and integrates scc output
|
|
72
|
-
- **Code exploration via `occ code`** — JS/TS, Vue SFC, and
|
|
72
|
+
- **Code exploration via `occ code`** — JS/TS, Vue SFC, Python, Go, Rust, Java, C/C++, Kotlin, and other tree-sitter-backed symbol lookup, exact `nodeId` source reads with `occ code source`, syntax checks with `occ code check`, content search, callers/callees, dependency categories, inheritance, module coupling, and ambiguity-aware chains
|
|
73
73
|
- **Repository map / pack via `occ code map` / `occ code pack`** — token-budgeted, PageRank-ranked repo map (top symbol signatures per file) or content pack, with a pluggable heuristic or BPE (`o200k_base` / `cl100k_base`) tokenizer for exact budgets, and opt-in query/path focus (`--query`, `--focus-path`, `--focus-depth`) to bias the map toward a specific task
|
|
74
74
|
- **Workspace analysis via `occ workspace`** — fast directory description plus combined code, document, and structure analysis with versioned JSON contracts, per-document summaries, and cross-reference detection
|
|
75
75
|
- **Git context via `occ git`** — changed files, diff summaries and token-bounded patches, commit/file history, and churn hotspots over a typed, shell-injection-safe git client; plus git-aware code (`occ code diff`, `occ code history`, `occ code map --changed-from`) that maps a diff to the code symbols it touches
|
|
@@ -148,6 +148,11 @@ occ code analyze callers createUser --path .
|
|
|
148
148
|
occ code analyze deps src/deps --path .
|
|
149
149
|
occ code analyze chain ambiguousCaller duplicate --path .
|
|
150
150
|
|
|
151
|
+
# Read one symbol body by nodeId, then check changed-file syntax
|
|
152
|
+
occ code map --path . --map-format json --map-tokens 4096
|
|
153
|
+
occ code source --path . --node-id "function:/abs/repo/src/main.ts:bootstrap:3" --format json
|
|
154
|
+
occ code check src/main.ts --path . --format json
|
|
155
|
+
|
|
151
156
|
# Module coupling metrics
|
|
152
157
|
occ code analyze coupling src/code --path .
|
|
153
158
|
|
|
@@ -267,7 +272,7 @@ Scanned 23 documents (56,750 words, 201 pages) in 120ms
|
|
|
267
272
|
|
|
268
273
|
`occ code` adds on-demand code exploration without changing the existing document-scan workflow. It builds an in-memory repository graph for each command and does not require a database, daemon, or background indexer.
|
|
269
274
|
|
|
270
|
-
The
|
|
275
|
+
The type-accurate path is **JavaScript, TypeScript, and Vue Single-File Components** (parsed with the TypeScript compiler). **Python, Go, Rust, Java, C/C++, C#, Kotlin, Scala, Swift, Ruby, and PHP** are parsed with vendored tree-sitter grammars for real symbols, calls, and inheritance. Any extension without a vendored grammar still parses name-only without failing.
|
|
271
276
|
|
|
272
277
|
```bash
|
|
273
278
|
# Exact symbol lookup
|
|
@@ -279,6 +284,14 @@ occ code find pattern service --path .
|
|
|
279
284
|
# Full-text content search
|
|
280
285
|
occ code find content normalize_name --path .
|
|
281
286
|
|
|
287
|
+
# Read exactly one symbol body by nodeId (from code map/find/index JSON) or by name
|
|
288
|
+
occ code map --path . --map-format json --map-tokens 4096
|
|
289
|
+
occ code source --path . --node-id "function:/abs/repo/src/main.ts:bootstrap:3" --format json
|
|
290
|
+
occ code source bootstrap --path . --file src/main.ts --type function
|
|
291
|
+
|
|
292
|
+
# Check syntax without a language server (exits nonzero only when invalid)
|
|
293
|
+
occ code check src/main.ts --path .
|
|
294
|
+
|
|
282
295
|
# Outgoing and incoming call analysis
|
|
283
296
|
occ code analyze calls bootstrap --path test/fixtures/code-explore
|
|
284
297
|
occ code analyze callers createUser --path test/fixtures/code-explore
|
|
@@ -314,6 +327,8 @@ Highlights of the current code exploration behavior:
|
|
|
314
327
|
- **Focused maps** via `--query`, `--focus-path` (repeatable), and `--focus-depth` — opt-in, additive relevance scoring (query + path + graph neighbors) blended with the global rank so task-relevant files surface within the budget; omitting the flags keeps the global PageRank overview unchanged
|
|
315
328
|
- **Change-aware exploration** via `occ code diff` (symbols touched by a git diff range, with removed-symbol recovery), `occ code history <symbol>` (git line history for a symbol), and `occ code map --changed-from <ref>` (diff-focused repo maps)
|
|
316
329
|
- **Exact, pattern, type, and content search** over the repository graph
|
|
330
|
+
- **Single-symbol source reads** via `occ code source` — read one symbol body by stable `nodeId` (from `occ code map` / `find` / `index` JSON) or a disambiguated name, reading file content on demand and refusing paths that escape the repo root
|
|
331
|
+
- **Language-server-free syntax checks** via `occ code check` — TS/JS, Vue SFC, Python, and the vendored tree-sitter languages; exits nonzero only when `valid` is false
|
|
317
332
|
- **Call analysis** with explicit `resolved`, `ambiguous`, and `unresolved` states
|
|
318
333
|
- **Receiver-aware method resolution** for `this`, `super`, `self`, and `cls`
|
|
319
334
|
- **Dependency analysis** grouped into local, external, and unresolved imports
|
|
@@ -473,50 +488,50 @@ const callGraph = session.toMermaid('call-graph', 'bootstrap');
|
|
|
473
488
|
|
|
474
489
|
Available subpath exports:
|
|
475
490
|
|
|
476
|
-
| Import path | Description
|
|
477
|
-
| ----------------------------------------------- |
|
|
478
|
-
| `@cesarandreslopez/occ/code/build` | `buildCodebaseIndex` — graph construction (with optional `maxFiles`/`maxBytes`/`onBudgetExceeded` budget controls and `CodeIndexBudgetExceededError`); also `parseCodeFiles` (bounded-concurrency parse pool) + `assembleCodebaseIndex` for staged indexing
|
|
479
|
-
| `@cesarandreslopez/occ/code/types` | TypeScript types (`CodebaseIndex`, `CodeNode`, `CodeEdge`, `IndexTruncation`, etc.)
|
|
480
|
-
| `@cesarandreslopez/occ/code/query` | Query functions (`findByName`, `analyzeCalls`, `analyzeDeps`, etc.)
|
|
481
|
-
| `@cesarandreslopez/occ/code/discover` | `discoverCodeFiles` — file discovery
|
|
482
|
-
| `@cesarandreslopez/occ/code/preview` | `previewCodebaseSize` — cheap size + per-language estimate without parsing, with budget pressure reporting
|
|
483
|
-
| `@cesarandreslopez/occ/code/isolated` | `buildCodebaseIndexIsolated` — runs `buildCodebaseIndex` in a forked subprocess, optionally returning a slim index
|
|
484
|
-
| `@cesarandreslopez/occ/code/incremental` | `computeManifestDiff`, `classifyChangedFiles`, `findResolutionImpactedFiles`, `spliceIndexInputs` — primitives behind incremental `update()`/`ensureFresh()` (manifest diff + resolution-impact + graph splice)
|
|
485
|
-
| `@cesarandreslopez/occ/code/slim` | `slimifyIndex`, `parseSlimIndex`, `validateSlimIndex` — content-free `CodebaseIndexSlim` for graph-only consumers
|
|
486
|
-
| `@cesarandreslopez/occ/code/chunk` | `chunkCodebase`, `chunkFromIndex`, `chunkFromIndexCooperative`, `chunkFromIndexStreaming` — semantic code chunking (word- or token-based via `maxTokens`/`countTokens`; the cooperative variant yields the event loop, the streaming variant reads each file on demand from a slim/`contentMode: 'none'` index)
|
|
487
|
-
| `@cesarandreslopez/occ/code/session` | `createCodeQuerySession` — stateful code query session (sync `chunk()` plus async `chunkCooperative()` that yields the event loop while chunking)
|
|
488
|
-
| `@cesarandreslopez/occ/code/store` | `openCodeIndexStore`, `openChunkCodeIndexStore` — persistent index store with cache strategies (the chunk variant pins `contentMode: 'full'`; `update(changedFiles?)` does a true incremental refresh — manifest diff + targeted re-parse + graph splice)
|
|
489
|
-
| `@cesarandreslopez/occ/code/cache` | Index caching utilities (legacy — prefer `./code/store`)
|
|
490
|
-
| `@cesarandreslopez/occ/code/diff` | `computeCodeDiff`, `joinHunksToSymbols` — map a git diff range to changed code symbols (added/removed/modified, new/removed exports, removed-symbol recovery)
|
|
491
|
-
| `@cesarandreslopez/occ/git` | Git context API — `getGitChangedFiles`, `getGitDiffSummary`, `getGitDiffPatch`, `getGitDiffHunks`, `getGitDiffFunctionContext`, `getGitCommitHistory`, `getGitFileHistory`, `getGitChurnSummary`, `resolveGitRange` (also `./git/types`, `./git/api`, `./git/client`, `./git/parse`)
|
|
492
|
-
| `@cesarandreslopez/occ/doc/inspect` | `inspectDocument` — document metadata and content extraction
|
|
493
|
-
| `@cesarandreslopez/occ/doc/types` | Document inspection types
|
|
494
|
-
| `@cesarandreslopez/occ/doc/discover` | Document file discovery (now includes prose formats by default; opt into data files via `includeDataFiles`; new `discoverDocumentSet` returns `{ documents, skipped }`)
|
|
495
|
-
| `@cesarandreslopez/occ/doc/batch` | Batch document inspection
|
|
496
|
-
| `@cesarandreslopez/occ/doc/chunk` | `chunkDocument` / `chunkDocumentFromMarkdown` — heading-aware, token-budgeted document chunker for DOCX/PDF/PPTX/XLSX/ODT/ODS/ODP/MD/MDX/TXT/RST/AsciiDoc (the `FromMarkdown` variant chunks pre-converted markdown without re-parsing)
|
|
497
|
-
| `@cesarandreslopez/occ/doc/entities` | Entity and keyword extraction
|
|
498
|
-
| `@cesarandreslopez/occ/doc/references` | Cross-reference detection
|
|
499
|
-
| `@cesarandreslopez/occ/workspace/analyze` | `analyzeWorkspace` — workspace-level analysis
|
|
500
|
-
| `@cesarandreslopez/occ/workspace/describe` | `describeWorkspace` — fast directory classification
|
|
501
|
-
| `@cesarandreslopez/occ/workspace/documents` | `inspectWorkspaceDocumentSet` — document summaries and cross-references
|
|
502
|
-
| `@cesarandreslopez/occ/workspace/types` | Workspace analysis types
|
|
503
|
-
| `@cesarandreslopez/occ/workspace/prepare` | `prepareWorkspaceContext` — combined code indexing + document inspection
|
|
504
|
-
| `@cesarandreslopez/occ/workspace/prepare-types` | Workspace preparation types (`WorkspacePrepareOptions`, `WorkspacePreparedContext`, etc.)
|
|
505
|
-
| `@cesarandreslopez/occ/workspace/bundle` | `bundleWorkspace` — single-call versioned `WorkspaceBundle` (description + analysis + documents + slim code index + outline + cross-refs + optional document / code / unified corpus chunks via `WorkspaceCorpusChunk`)
|
|
506
|
-
| `@cesarandreslopez/occ/markdown/convert` | `documentToMarkdown` — document-to-markdown conversion (now reads MD/MDX/TXT/RST/AsciiDoc/YAML/JSON/TOML directly)
|
|
507
|
-
| `@cesarandreslopez/occ/structure/extract` | `extractFromMarkdown` — heading tree extraction
|
|
508
|
-
| `@cesarandreslopez/occ/structure/types` | Structure types and helpers
|
|
509
|
-
| `@cesarandreslopez/occ/sheet/inspect` | `inspectWorkbook` — XLSX workbook inspection
|
|
510
|
-
| `@cesarandreslopez/occ/sheet/types` | Sheet inspection types
|
|
511
|
-
| `@cesarandreslopez/occ/slide/inspect` | `inspectPresentation` — presentation inspection
|
|
512
|
-
| `@cesarandreslopez/occ/table/inspect` | Table extraction from documents
|
|
513
|
-
| `@cesarandreslopez/occ/table/types` | Table extraction types
|
|
514
|
-
| `@cesarandreslopez/occ/health` | `health()` — liveness probe with version + capability flags
|
|
515
|
-
| `@cesarandreslopez/occ/errors` | `OccAbortError`, `OCC_ABORTED`, `isOccAbortError` — typed abort error that survives `instanceof` across forked subprocesses
|
|
516
|
-
| `@cesarandreslopez/occ/types` | Shared types (`ConfidenceLevel`, `ParseResult`, `ParserOutput`, etc.)
|
|
517
|
-
| `@cesarandreslopez/occ/tokens` | Token estimation utilities
|
|
518
|
-
| `@cesarandreslopez/occ/progress-event` | Progress event types (`ProgressPhase`, `ProgressEvent` with optional `scope`/`currentPath`/`bytesProcessed`/`totalBytes`/`startedAt`/`elapsedMs`)
|
|
519
|
-
| `@cesarandreslopez/occ/stats` | Stats types (`StatsRow`, `AggregateResult`) and `aggregate()`
|
|
491
|
+
| Import path | Description |
|
|
492
|
+
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
493
|
+
| `@cesarandreslopez/occ/code/build` | `buildCodebaseIndex` — graph construction (with optional `maxFiles`/`maxBytes`/`onBudgetExceeded` budget controls and `CodeIndexBudgetExceededError`); also `parseCodeFiles` (bounded-concurrency parse pool) + `assembleCodebaseIndex` for staged indexing |
|
|
494
|
+
| `@cesarandreslopez/occ/code/types` | TypeScript types (`CodebaseIndex`, `CodeNode`, `CodeEdge`, `IndexTruncation`, etc.) |
|
|
495
|
+
| `@cesarandreslopez/occ/code/query` | Query functions (`findByName`, `analyzeCalls`, `analyzeDeps`, etc.) |
|
|
496
|
+
| `@cesarandreslopez/occ/code/discover` | `discoverCodeFiles` — file discovery |
|
|
497
|
+
| `@cesarandreslopez/occ/code/preview` | `previewCodebaseSize` — cheap size + per-language estimate without parsing, with budget pressure reporting |
|
|
498
|
+
| `@cesarandreslopez/occ/code/isolated` | `buildCodebaseIndexIsolated` — runs `buildCodebaseIndex` in a forked subprocess, optionally returning a slim index; also `chunkFromStoreIsolated` — runs store-backed code chunking in a forked subprocess (options `ChunkFromStoreIsolatedOptions`, `SerializableCodeChunkOptions`) |
|
|
499
|
+
| `@cesarandreslopez/occ/code/incremental` | `computeManifestDiff`, `classifyChangedFiles`, `findResolutionImpactedFiles`, `spliceIndexInputs` — primitives behind incremental `update()`/`ensureFresh()` (manifest diff + resolution-impact + graph splice) |
|
|
500
|
+
| `@cesarandreslopez/occ/code/slim` | `slimifyIndex`, `parseSlimIndex`, `validateSlimIndex` — content-free `CodebaseIndexSlim` for graph-only consumers |
|
|
501
|
+
| `@cesarandreslopez/occ/code/chunk` | `chunkCodebase`, `chunkFromIndex`, `chunkFromIndexCooperative`, `chunkFromIndexStreaming` — semantic code chunking (word- or token-based via `maxTokens`/`countTokens`; the cooperative variant yields the event loop, the streaming variant reads each file on demand from a slim/`contentMode: 'none'` index) |
|
|
502
|
+
| `@cesarandreslopez/occ/code/session` | `createCodeQuerySession` — stateful code query session (sync `chunk()` plus async `chunkCooperative()` that yields the event loop while chunking) |
|
|
503
|
+
| `@cesarandreslopez/occ/code/store` | `openCodeIndexStore`, `openChunkCodeIndexStore` — persistent index store with cache strategies (the chunk variant pins `contentMode: 'full'`; `update(changedFiles?)` does a true incremental refresh — manifest diff + targeted re-parse + graph splice; `chunkIsolated(options?)` chunks the cached index in a forked subprocess) |
|
|
504
|
+
| `@cesarandreslopez/occ/code/cache` | Index caching utilities (legacy — prefer `./code/store`) |
|
|
505
|
+
| `@cesarandreslopez/occ/code/diff` | `computeCodeDiff`, `joinHunksToSymbols` — map a git diff range to changed code symbols (added/removed/modified, new/removed exports, removed-symbol recovery) |
|
|
506
|
+
| `@cesarandreslopez/occ/git` | Git context API — `getGitChangedFiles`, `getGitDiffSummary`, `getGitDiffPatch`, `getGitDiffHunks`, `getGitDiffFunctionContext`, `getGitCommitHistory`, `getGitFileHistory`, `getGitChurnSummary`, `resolveGitRange` (also `./git/types`, `./git/api`, `./git/client`, `./git/parse`) |
|
|
507
|
+
| `@cesarandreslopez/occ/doc/inspect` | `inspectDocument` — document metadata and content extraction |
|
|
508
|
+
| `@cesarandreslopez/occ/doc/types` | Document inspection types |
|
|
509
|
+
| `@cesarandreslopez/occ/doc/discover` | Document file discovery (now includes prose formats by default; opt into data files via `includeDataFiles`; new `discoverDocumentSet` returns `{ documents, skipped }`) |
|
|
510
|
+
| `@cesarandreslopez/occ/doc/batch` | Batch document inspection |
|
|
511
|
+
| `@cesarandreslopez/occ/doc/chunk` | `chunkDocument` / `chunkDocumentFromMarkdown` — heading-aware, token-budgeted document chunker for DOCX/PDF/PPTX/XLSX/ODT/ODS/ODP/MD/MDX/TXT/RST/AsciiDoc (the `FromMarkdown` variant chunks pre-converted markdown without re-parsing) |
|
|
512
|
+
| `@cesarandreslopez/occ/doc/entities` | Entity and keyword extraction |
|
|
513
|
+
| `@cesarandreslopez/occ/doc/references` | Cross-reference detection |
|
|
514
|
+
| `@cesarandreslopez/occ/workspace/analyze` | `analyzeWorkspace` — workspace-level analysis |
|
|
515
|
+
| `@cesarandreslopez/occ/workspace/describe` | `describeWorkspace` — fast directory classification |
|
|
516
|
+
| `@cesarandreslopez/occ/workspace/documents` | `inspectWorkspaceDocumentSet` — document summaries and cross-references |
|
|
517
|
+
| `@cesarandreslopez/occ/workspace/types` | Workspace analysis types |
|
|
518
|
+
| `@cesarandreslopez/occ/workspace/prepare` | `prepareWorkspaceContext` — combined code indexing + document inspection |
|
|
519
|
+
| `@cesarandreslopez/occ/workspace/prepare-types` | Workspace preparation types (`WorkspacePrepareOptions`, `WorkspacePreparedContext`, etc.) |
|
|
520
|
+
| `@cesarandreslopez/occ/workspace/bundle` | `bundleWorkspace` — single-call versioned `WorkspaceBundle` (description + analysis + documents + slim code index + outline + cross-refs + optional document / code / unified corpus chunks via `WorkspaceCorpusChunk`) |
|
|
521
|
+
| `@cesarandreslopez/occ/markdown/convert` | `documentToMarkdown` — document-to-markdown conversion (now reads MD/MDX/TXT/RST/AsciiDoc/YAML/JSON/TOML directly) |
|
|
522
|
+
| `@cesarandreslopez/occ/structure/extract` | `extractFromMarkdown` — heading tree extraction |
|
|
523
|
+
| `@cesarandreslopez/occ/structure/types` | Structure types and helpers |
|
|
524
|
+
| `@cesarandreslopez/occ/sheet/inspect` | `inspectWorkbook` — XLSX workbook inspection |
|
|
525
|
+
| `@cesarandreslopez/occ/sheet/types` | Sheet inspection types |
|
|
526
|
+
| `@cesarandreslopez/occ/slide/inspect` | `inspectPresentation` — presentation inspection |
|
|
527
|
+
| `@cesarandreslopez/occ/table/inspect` | Table extraction from documents |
|
|
528
|
+
| `@cesarandreslopez/occ/table/types` | Table extraction types |
|
|
529
|
+
| `@cesarandreslopez/occ/health` | `health()` — liveness probe with version + capability flags |
|
|
530
|
+
| `@cesarandreslopez/occ/errors` | `OccAbortError`, `OCC_ABORTED`, `isOccAbortError` — typed abort error that survives `instanceof` across forked subprocesses |
|
|
531
|
+
| `@cesarandreslopez/occ/types` | Shared types (`ConfidenceLevel`, `ParseResult`, `ParserOutput`, etc.) |
|
|
532
|
+
| `@cesarandreslopez/occ/tokens` | Token estimation utilities |
|
|
533
|
+
| `@cesarandreslopez/occ/progress-event` | Progress event types (`ProgressPhase`, `ProgressEvent` with optional `scope`/`currentPath`/`bytesProcessed`/`totalBytes`/`startedAt`/`elapsedMs`, plus off-thread bundle-read timing fields `section`/`parentReadStartedAt`/`parentReadFinishedAt`/`parentReadDurationMs`/`sectionStartedAt`/`sectionFinishedAt`/`sectionDurationMs`/`cleanupDurationMs`) |
|
|
534
|
+
| `@cesarandreslopez/occ/stats` | Stats types (`StatsRow`, `AggregateResult`) and `aggregate()` |
|
|
520
535
|
|
|
521
536
|
TypeScript ships with OCC as a direct dependency, so the code exploration module works after a normal install. You only need a separate TypeScript setup if your own project uses `tsc`.
|
|
522
537
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface CheckCodeSyntaxOptions {
|
|
2
|
+
repoRoot: string;
|
|
3
|
+
file: string;
|
|
4
|
+
}
|
|
5
|
+
export interface CodeSyntaxDiagnostic {
|
|
6
|
+
message: string;
|
|
7
|
+
line?: number;
|
|
8
|
+
column?: number;
|
|
9
|
+
code?: string | number;
|
|
10
|
+
source?: string;
|
|
11
|
+
severity: 'error' | 'warning';
|
|
12
|
+
}
|
|
13
|
+
export type CheckCodeSyntaxResult = {
|
|
14
|
+
status: 'checked';
|
|
15
|
+
supported: true;
|
|
16
|
+
valid: boolean;
|
|
17
|
+
path: string;
|
|
18
|
+
relativePath: string;
|
|
19
|
+
language: string;
|
|
20
|
+
diagnostics: CodeSyntaxDiagnostic[];
|
|
21
|
+
} | {
|
|
22
|
+
status: 'unsupported';
|
|
23
|
+
supported: false;
|
|
24
|
+
valid?: undefined;
|
|
25
|
+
path: string;
|
|
26
|
+
relativePath: string;
|
|
27
|
+
language: string;
|
|
28
|
+
diagnostics: [];
|
|
29
|
+
} | {
|
|
30
|
+
status: 'error';
|
|
31
|
+
supported: false;
|
|
32
|
+
valid: false;
|
|
33
|
+
path?: string;
|
|
34
|
+
relativePath?: string;
|
|
35
|
+
language?: string;
|
|
36
|
+
diagnostics: CodeSyntaxDiagnostic[];
|
|
37
|
+
message: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function checkCodeSyntax(options: CheckCodeSyntaxOptions): Promise<CheckCodeSyntaxResult>;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { getLanguageSpec } from './languages.js';
|
|
7
|
+
import { collectTreeSitterErrorNodes, parseTreeSitterContent } from './tree-sitter.js';
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
let typescriptModulePromise;
|
|
10
|
+
function loadTypescript() {
|
|
11
|
+
typescriptModulePromise ??= import('typescript');
|
|
12
|
+
return typescriptModulePromise;
|
|
13
|
+
}
|
|
14
|
+
function resolveWithinRepo(repoRoot, file) {
|
|
15
|
+
const root = path.resolve(repoRoot);
|
|
16
|
+
const resolved = path.isAbsolute(file) ? path.resolve(file) : path.resolve(root, file);
|
|
17
|
+
const relativePath = path.relative(root, resolved);
|
|
18
|
+
if (relativePath === '' || relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
19
|
+
return `Resolved path "${file}" is outside repo root "${root}".`;
|
|
20
|
+
}
|
|
21
|
+
return { path: resolved, relativePath: relativePath.split(path.sep).join('/') };
|
|
22
|
+
}
|
|
23
|
+
function languageForExtension(filePath) {
|
|
24
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
25
|
+
switch (extension) {
|
|
26
|
+
case '.ts':
|
|
27
|
+
case '.tsx':
|
|
28
|
+
return 'typescript';
|
|
29
|
+
case '.js':
|
|
30
|
+
case '.jsx':
|
|
31
|
+
case '.mjs':
|
|
32
|
+
case '.cjs':
|
|
33
|
+
return 'javascript';
|
|
34
|
+
case '.vue':
|
|
35
|
+
return 'vue';
|
|
36
|
+
case '.py':
|
|
37
|
+
return 'python';
|
|
38
|
+
default:
|
|
39
|
+
return extension.replace(/^\./, '') || 'unknown';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function diagnosticFromError(error, source) {
|
|
43
|
+
const maybeError = error instanceof Error ? error : new Error(String(error));
|
|
44
|
+
const loc = error;
|
|
45
|
+
const start = loc.loc?.start ?? loc.loc;
|
|
46
|
+
const line = typeof start?.line === 'number' ? start.line : undefined;
|
|
47
|
+
const column = typeof start?.column === 'number' ? start.column + 1 : undefined;
|
|
48
|
+
return {
|
|
49
|
+
message: maybeError.message,
|
|
50
|
+
line,
|
|
51
|
+
column,
|
|
52
|
+
source,
|
|
53
|
+
severity: 'error',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function checkTypeScriptLike(filePath, content, language) {
|
|
57
|
+
const ts = await loadTypescript();
|
|
58
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
59
|
+
const scriptKind = extension === '.tsx'
|
|
60
|
+
? ts.ScriptKind.TSX
|
|
61
|
+
: extension === '.jsx'
|
|
62
|
+
? ts.ScriptKind.JSX
|
|
63
|
+
: language === 'javascript'
|
|
64
|
+
? ts.ScriptKind.JS
|
|
65
|
+
: ts.ScriptKind.TS;
|
|
66
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, scriptKind);
|
|
67
|
+
const parseDiagnostics = sourceFile.parseDiagnostics;
|
|
68
|
+
return parseDiagnostics.map((diagnostic) => {
|
|
69
|
+
const position = diagnostic.start == null ? undefined : sourceFile.getLineAndCharacterOfPosition(diagnostic.start);
|
|
70
|
+
return {
|
|
71
|
+
message: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'),
|
|
72
|
+
line: position ? position.line + 1 : undefined,
|
|
73
|
+
column: position ? position.character + 1 : undefined,
|
|
74
|
+
code: diagnostic.code,
|
|
75
|
+
source: 'typescript',
|
|
76
|
+
severity: 'error',
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async function checkVue(filePath, content) {
|
|
81
|
+
const compiler = await import('@vue/compiler-sfc');
|
|
82
|
+
const parsed = compiler.parse(content, { filename: filePath });
|
|
83
|
+
const diagnostics = parsed.errors.map(error => diagnosticFromError(error, 'vue'));
|
|
84
|
+
if (diagnostics.length > 0)
|
|
85
|
+
return diagnostics;
|
|
86
|
+
if (!parsed.descriptor.script && !parsed.descriptor.scriptSetup)
|
|
87
|
+
return diagnostics;
|
|
88
|
+
try {
|
|
89
|
+
const compiled = compiler.compileScript(parsed.descriptor, { id: 'occ-check' });
|
|
90
|
+
diagnostics.push(...(await checkTypeScriptLike(filePath, compiled.content, 'typescript')));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
diagnostics.push(diagnosticFromError(error, 'vue'));
|
|
94
|
+
}
|
|
95
|
+
return diagnostics;
|
|
96
|
+
}
|
|
97
|
+
function isMissingExecutable(error) {
|
|
98
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
99
|
+
}
|
|
100
|
+
function pythonDiagnostic(stderr) {
|
|
101
|
+
const lineMatch = stderr.match(/line (\d+)/);
|
|
102
|
+
const message = stderr
|
|
103
|
+
.split(/\r?\n/)
|
|
104
|
+
.map(line => line.trim())
|
|
105
|
+
.filter(Boolean)
|
|
106
|
+
.at(-1);
|
|
107
|
+
return {
|
|
108
|
+
message: message ?? (stderr.trim() || 'Python syntax error'),
|
|
109
|
+
line: lineMatch ? Number(lineMatch[1]) : undefined,
|
|
110
|
+
source: 'python',
|
|
111
|
+
severity: 'error',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
async function checkPython(filePath) {
|
|
115
|
+
const script = [
|
|
116
|
+
'import ast, pathlib, sys',
|
|
117
|
+
'path = sys.argv[1]',
|
|
118
|
+
"source = pathlib.Path(path).read_text(encoding='utf8')",
|
|
119
|
+
'ast.parse(source, filename=path)',
|
|
120
|
+
].join('\n');
|
|
121
|
+
try {
|
|
122
|
+
await execFileAsync('python3', ['-c', script, filePath], { timeout: 5_000, maxBuffer: 1_000_000 });
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (isMissingExecutable(error))
|
|
127
|
+
return 'unsupported';
|
|
128
|
+
const execError = error;
|
|
129
|
+
const stderr = typeof execError.stderr === 'string' ? execError.stderr : String(execError.stderr ?? '');
|
|
130
|
+
return [pythonDiagnostic(stderr)];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function checkTreeSitter(grammar, content) {
|
|
134
|
+
const tree = await parseTreeSitterContent(grammar, content);
|
|
135
|
+
if (!tree)
|
|
136
|
+
return 'unsupported';
|
|
137
|
+
// Free the WASM tree handle once the error nodes are copied into plain diagnostics.
|
|
138
|
+
try {
|
|
139
|
+
return collectTreeSitterErrorNodes(tree.rootNode).map(error => ({
|
|
140
|
+
message: error.type === 'ERROR' ? 'Syntax error' : `Missing syntax node: ${error.text || error.type}`,
|
|
141
|
+
line: error.line,
|
|
142
|
+
column: error.column,
|
|
143
|
+
source: 'tree-sitter',
|
|
144
|
+
severity: 'error',
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
tree.delete();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export async function checkCodeSyntax(options) {
|
|
152
|
+
const resolved = resolveWithinRepo(options.repoRoot, options.file);
|
|
153
|
+
if (typeof resolved === 'string') {
|
|
154
|
+
return {
|
|
155
|
+
status: 'error',
|
|
156
|
+
supported: false,
|
|
157
|
+
valid: false,
|
|
158
|
+
diagnostics: [{ message: resolved, severity: 'error', source: 'occ' }],
|
|
159
|
+
message: resolved,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (!existsSync(resolved.path)) {
|
|
163
|
+
const message = `File not found: ${resolved.relativePath}`;
|
|
164
|
+
return {
|
|
165
|
+
status: 'error',
|
|
166
|
+
supported: false,
|
|
167
|
+
valid: false,
|
|
168
|
+
path: resolved.path,
|
|
169
|
+
relativePath: resolved.relativePath,
|
|
170
|
+
diagnostics: [{ message, severity: 'error', source: 'occ' }],
|
|
171
|
+
message,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const language = languageForExtension(resolved.path);
|
|
175
|
+
const extension = path.extname(resolved.path).toLowerCase();
|
|
176
|
+
const spec = getLanguageSpec(resolved.path);
|
|
177
|
+
if (extension === '.py') {
|
|
178
|
+
let diagnostics = await checkPython(resolved.path);
|
|
179
|
+
if (diagnostics === 'unsupported' && spec?.treeSitter) {
|
|
180
|
+
// python3 isn't on PATH (e.g. Windows) — fall back to the vendored tree-sitter grammar.
|
|
181
|
+
const content = await readFile(resolved.path, 'utf8');
|
|
182
|
+
diagnostics = await checkTreeSitter(spec.treeSitter.grammar, content);
|
|
183
|
+
}
|
|
184
|
+
if (diagnostics === 'unsupported') {
|
|
185
|
+
return {
|
|
186
|
+
status: 'unsupported',
|
|
187
|
+
supported: false,
|
|
188
|
+
path: resolved.path,
|
|
189
|
+
relativePath: resolved.relativePath,
|
|
190
|
+
language,
|
|
191
|
+
diagnostics: [],
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
status: 'checked',
|
|
196
|
+
supported: true,
|
|
197
|
+
valid: diagnostics.length === 0,
|
|
198
|
+
path: resolved.path,
|
|
199
|
+
relativePath: resolved.relativePath,
|
|
200
|
+
language,
|
|
201
|
+
diagnostics,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
if (!['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.vue'].includes(extension) && !spec?.treeSitter) {
|
|
205
|
+
return {
|
|
206
|
+
status: 'unsupported',
|
|
207
|
+
supported: false,
|
|
208
|
+
path: resolved.path,
|
|
209
|
+
relativePath: resolved.relativePath,
|
|
210
|
+
language,
|
|
211
|
+
diagnostics: [],
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const content = await readFile(resolved.path, 'utf8');
|
|
215
|
+
const diagnostics = extension === '.vue'
|
|
216
|
+
? await checkVue(resolved.path, content)
|
|
217
|
+
: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'].includes(extension)
|
|
218
|
+
? await checkTypeScriptLike(resolved.path, content, language)
|
|
219
|
+
: spec?.treeSitter
|
|
220
|
+
? await checkTreeSitter(spec.treeSitter.grammar, content)
|
|
221
|
+
: 'unsupported';
|
|
222
|
+
if (diagnostics === 'unsupported') {
|
|
223
|
+
return {
|
|
224
|
+
status: 'unsupported',
|
|
225
|
+
supported: false,
|
|
226
|
+
path: resolved.path,
|
|
227
|
+
relativePath: resolved.relativePath,
|
|
228
|
+
language,
|
|
229
|
+
diagnostics: [],
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
status: 'checked',
|
|
234
|
+
supported: true,
|
|
235
|
+
valid: diagnostics.length === 0,
|
|
236
|
+
path: resolved.path,
|
|
237
|
+
relativePath: resolved.relativePath,
|
|
238
|
+
language,
|
|
239
|
+
diagnostics,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/code/check.ts"],"names":[],"mappings":"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"}
|
package/dist/src/code/command.js
CHANGED
|
@@ -5,10 +5,12 @@ import { z } from 'zod';
|
|
|
5
5
|
import { buildCodebaseIndex } from './build.js';
|
|
6
6
|
import { writeStream } from '../utils.js';
|
|
7
7
|
import { parsePositiveInt } from '../cli-validation.js';
|
|
8
|
+
import { checkCodeSyntax } from './check.js';
|
|
8
9
|
import { analyzeCallChain, analyzeCallers, analyzeCalls, analyzeDeps, analyzeModuleCoupling, analyzeTree, createPayload, findByName, findByPattern, findByType, findContent, fusedSearch, } from './query.js';
|
|
9
10
|
import { formatCodeDiff, formatCodeDiffJson, formatChains, formatClassTree, formatContentResults, formatDependencies, formatFusedResults, formatModuleCoupling, formatPayloadJson, formatRelationResults, formatSearchResults, renderRepoMap, } from './output.js';
|
|
10
11
|
import { computeCodeDiff } from './diff.js';
|
|
11
12
|
import { buildRepoMap } from './map.js';
|
|
13
|
+
import { readCodeSource } from './source.js';
|
|
12
14
|
import { createTokenizer, resolveTokenizerName } from '../tokens.js';
|
|
13
15
|
import { getGitDiffSummary, getGitFileHistory } from '../git/api.js';
|
|
14
16
|
const CodeCommandOptionsSchema = z
|
|
@@ -44,6 +46,7 @@ const CodeCommandOptionsSchema = z
|
|
|
44
46
|
staged: z.boolean().optional(),
|
|
45
47
|
changedFrom: z.string().optional(),
|
|
46
48
|
changedTo: z.string().optional(),
|
|
49
|
+
nodeId: z.string().optional(),
|
|
47
50
|
})
|
|
48
51
|
.passthrough();
|
|
49
52
|
function getOptions(command) {
|
|
@@ -89,6 +92,31 @@ async function emit(output, options) {
|
|
|
89
92
|
}
|
|
90
93
|
await writeStream(process.stdout, output);
|
|
91
94
|
}
|
|
95
|
+
function formatSourceResult(result) {
|
|
96
|
+
if (result.status === 'resolved')
|
|
97
|
+
return result.source;
|
|
98
|
+
const candidates = 'candidates' in result && result.candidates.length > 0
|
|
99
|
+
? `\n${result.candidates
|
|
100
|
+
.map(candidate => `- ${candidate.name} ${candidate.relativePath ?? candidate.path}:${candidate.line ?? '?'}`)
|
|
101
|
+
.join('\n')}`
|
|
102
|
+
: '';
|
|
103
|
+
return `${result.status}: ${result.message}${candidates}`;
|
|
104
|
+
}
|
|
105
|
+
function formatCheckResult(result) {
|
|
106
|
+
if (result.status === 'unsupported')
|
|
107
|
+
return `unsupported: ${result.relativePath}`;
|
|
108
|
+
if (result.status === 'error')
|
|
109
|
+
return `error: ${result.message}`;
|
|
110
|
+
if (result.valid)
|
|
111
|
+
return `valid: ${result.relativePath}`;
|
|
112
|
+
return [
|
|
113
|
+
`invalid: ${result.relativePath}`,
|
|
114
|
+
...result.diagnostics.map(diagnostic => {
|
|
115
|
+
const location = diagnostic.line ? `:${diagnostic.line}${diagnostic.column ? `:${diagnostic.column}` : ''}` : '';
|
|
116
|
+
return `- ${diagnostic.source ?? 'syntax'}${location}: ${diagnostic.message}`;
|
|
117
|
+
}),
|
|
118
|
+
].join('\n');
|
|
119
|
+
}
|
|
92
120
|
function resolveContentMode(value, fallback) {
|
|
93
121
|
if (!value)
|
|
94
122
|
return fallback;
|
|
@@ -260,6 +288,42 @@ export function registerCodeCommands(program) {
|
|
|
260
288
|
const output = options.format === 'json' ? formatPayloadJson(payload) : formatContentResults(results, options.ci);
|
|
261
289
|
await emit(output.endsWith('\n') ? output : `${output}\n`, options);
|
|
262
290
|
});
|
|
291
|
+
const sourceCmd = code.command('source [name]').description('Read one symbol body by node id or disambiguated name');
|
|
292
|
+
addSharedOptions(sourceCmd, { includeFile: true, includeType: true });
|
|
293
|
+
sourceCmd.option('--node-id <id>', 'exact node id from code map/find/index output');
|
|
294
|
+
sourceCmd.action(async (name, _options, command) => {
|
|
295
|
+
const options = getOptions(command);
|
|
296
|
+
if (options.nodeId && name) {
|
|
297
|
+
throw new Error('Use either --node-id or a symbol name, not both.');
|
|
298
|
+
}
|
|
299
|
+
if (!options.nodeId && !name) {
|
|
300
|
+
throw new Error('Provide --node-id <id> or a symbol name.');
|
|
301
|
+
}
|
|
302
|
+
const index = await withIndex(options, 'none');
|
|
303
|
+
const query = options.nodeId
|
|
304
|
+
? { nodeId: options.nodeId }
|
|
305
|
+
: { name: name ?? '', file: options.file, type: parseType(options.type) };
|
|
306
|
+
const result = await readCodeSource(index, query);
|
|
307
|
+
// Signal failure to scripts/agents when the symbol can't be uniquely resolved
|
|
308
|
+
// (not_found / ambiguous / error), mirroring `check`'s valid===false exit gate.
|
|
309
|
+
if (result.status !== 'resolved') {
|
|
310
|
+
process.exitCode = 1;
|
|
311
|
+
}
|
|
312
|
+
const output = options.format === 'json' ? JSON.stringify(result, null, 2) : formatSourceResult(result);
|
|
313
|
+
await emit(output.endsWith('\n') ? output : `${output}\n`, options);
|
|
314
|
+
});
|
|
315
|
+
const checkCmd = code.command('check <file>').description('Check syntax for a source file without a language server');
|
|
316
|
+
addSharedOptions(checkCmd);
|
|
317
|
+
checkCmd.action(async (file, _options, command) => {
|
|
318
|
+
const options = getOptions(command);
|
|
319
|
+
const repoRoot = path.resolve(options.path ?? process.cwd());
|
|
320
|
+
const result = await checkCodeSyntax({ repoRoot, file });
|
|
321
|
+
if (result.valid === false) {
|
|
322
|
+
process.exitCode = 1;
|
|
323
|
+
}
|
|
324
|
+
const output = options.format === 'json' ? JSON.stringify(result, null, 2) : formatCheckResult(result);
|
|
325
|
+
await emit(output.endsWith('\n') ? output : `${output}\n`, options);
|
|
326
|
+
});
|
|
263
327
|
const analyzeCallsCmd = analyze.command('calls <functionName>').description('Show what a function calls');
|
|
264
328
|
addSharedOptions(analyzeCallsCmd, { includeFile: true });
|
|
265
329
|
analyzeCallsCmd.action(async (functionName, _options, command) => {
|