refactor: curate public API surface (ROADMAP 3.6, 3.7)#430
Conversation
Mark 3.6 (CLI Command Objects) complete — already shipped in #427. Implement 3.7: reduce index.js from ~190 named exports to 48 curated exports. Keep only *Data() query functions, graph building, export formats, and essential constants. Remove CLI formatters, DB internals, parser internals, infrastructure helpers, and implementation-detail constants from the public surface. All removed exports remain importable via direct paths. Add ./cli entry point to package.json exports field.
|
Claude finished @carlos-alm's task —— View job PR Review CompleteRoot Cause AnalysisProblem Being Solved: Completing Phase 3.7 of the ROADMAP — curating the public API surface from ~190 exports to 48 focused exports. This reduces the API surface area while maintaining all functionality via direct imports. Why This Approach: The roadmap explicitly calls for API curation as part of architectural refactoring. The approach is justified — keeps *Data() functions, core building/search functions, and essential constants while removing internal implementation details from the public surface. Risk Assessment: Low risk. All removed exports remain importable via direct paths, ensuring no breaking changes for users who need internal functionality. Code Quality Assessment✅ Changes are Well-Targeted
✅ Roadmap Alignment
✅ Backwards Compatibility
✅ No Configuration Violations
Export Count VerificationBased on manual analysis of
Total: ~51 exports (close to claimed 48, within reasonable margin for counting methodology) Minor Issues
Final Recommendation
Strengths:
Recommendation: Merge after confirming test suite passes. |
Greptile SummaryThis PR completes ROADMAP items 3.6 and 3.7: it marks the CLI command-object refactor (already shipped in #427) as done, and reduces
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
Consumer["External consumer\nimport from '@optave/codegraph'"]
CLI["CLI consumer\nimport from '@optave/codegraph/cli'"]
PKG["Tool / bundler\nimport '@optave/codegraph/package.json'"]
subgraph exports ["package.json exports map"]
E1["'.' → src/index.js"]
E2["'./cli' → src/cli.js ✨ NEW"]
E3["'./package.json' → package.json"]
end
subgraph index ["src/index.js (48 curated exports)"]
QF["34 *Data() query functions"]
GB["4 graph building\nbuildGraph · loadConfig\nfindCycles · buildEmbeddings"]
EF["3 export formats\nexportDOT · exportJSON · exportMermaid"]
SR["3 search\nsearchData · multiSearchData · hybridSearchData"]
CN["4 constants\nEVERY_SYMBOL_KIND · EVERY_EDGE_KIND\nEXTENSIONS · IGNORE_DIRS"]
end
REMOVED["~145 removed exports\n(DB internals, parser internals,\nCLI formatters, infra helpers…)\nstill importable via direct\nrelative paths inside the package"]
Consumer --> E1 --> index
CLI --> E2 --> src_cli["src/cli.js\n(bin thin-wrapper)"]
PKG --> E3
E1 -. "previously also exported" .-> REMOVED
Last reviewed commit: 6cd318a |
src/index.js
Outdated
| // ── Graph Building & Search ───────────────────────────────────────────── | ||
| export { buildGraph } from './builder.js'; | ||
| export { cfgData } from './cfg.js'; | ||
| export { checkData } from './check.js'; | ||
| // Co-change analysis | ||
| export { | ||
| analyzeCoChanges, | ||
| coChangeData, | ||
| coChangeForFiles, | ||
| coChangeTopData, | ||
| computeCoChanges, | ||
| scanGitHistory, | ||
| } from './cochange.js'; | ||
| export { audit } from './commands/audit.js'; | ||
| export { batch, batchQuery } from './commands/batch.js'; | ||
| export { cfg } from './commands/cfg.js'; | ||
| export { check } from './commands/check.js'; | ||
| export { communities } from './commands/communities.js'; | ||
| export { complexity } from './commands/complexity.js'; | ||
| export { dataflow } from './commands/dataflow.js'; | ||
| export { manifesto } from './commands/manifesto.js'; | ||
| export { owners } from './commands/owners.js'; | ||
| export { sequence } from './commands/sequence.js'; | ||
| export { formatHotspots, formatModuleBoundaries, formatStructure } from './commands/structure.js'; | ||
| export { triage } from './commands/triage.js'; | ||
| // Community detection | ||
| export { communitiesData, communitySummaryForStats } from './communities.js'; | ||
| // Complexity metrics | ||
| export { | ||
| COMPLEXITY_RULES, | ||
| complexityData, | ||
| computeFunctionComplexity, | ||
| computeHalsteadMetrics, | ||
| computeLOCMetrics, | ||
| computeMaintainabilityIndex, | ||
| findFunctionNode, | ||
| HALSTEAD_RULES, | ||
| iterComplexity, | ||
| } from './complexity.js'; | ||
| // Configuration | ||
| export { coChangeData } from './cochange.js'; | ||
| export { communitiesData } from './communities.js'; | ||
| export { complexityData } from './complexity.js'; | ||
| export { loadConfig } from './config.js'; | ||
| // Shared constants | ||
| export { EXTENSIONS, IGNORE_DIRS, normalizePath } from './constants.js'; | ||
| // Circular dependency detection | ||
| export { findCycles, formatCycles } from './cycles.js'; | ||
| // Dataflow analysis | ||
| export { | ||
| buildDataflowEdges, | ||
| dataflowData, | ||
| dataflowImpactData, | ||
| dataflowPathData, | ||
| extractDataflow, | ||
| } from './dataflow.js'; | ||
| // Database utilities | ||
| export { | ||
| countEdges, | ||
| countFiles, | ||
| countNodes, | ||
| fanInJoinSQL, | ||
| fanOutJoinSQL, | ||
| findDbPath, | ||
| findNodesForTriage, | ||
| findNodesWithFanIn, | ||
| getBuildMeta, | ||
| initSchema, | ||
| iterateFunctionNodes, | ||
| kindInClause, | ||
| listFunctionNodes, | ||
| NodeQuery, | ||
| openDb, | ||
| openReadonlyOrFail, | ||
| setBuildMeta, | ||
| testFilterSQL, | ||
| } from './db.js'; | ||
| // Embeddings | ||
| // ── Constants ─────────────────────────────────────────────────────────── | ||
| export { EXTENSIONS, IGNORE_DIRS } from './constants.js'; | ||
| export { findCycles } from './cycles.js'; | ||
| export { dataflowData } from './dataflow.js'; | ||
| export { buildEmbeddings, hybridSearchData, multiSearchData, searchData } from './embedder.js'; | ||
| // ── Export Formats ────────────────────────────────────────────────────── | ||
| export { exportDOT, exportJSON, exportMermaid } from './export.js'; | ||
| export { flowData, listEntryPointsData } from './flow.js'; | ||
| export { EVERY_EDGE_KIND, EVERY_SYMBOL_KIND } from './kinds.js'; | ||
| export { manifestoData } from './manifesto.js'; | ||
| export { ownersData } from './owners.js'; | ||
| export { | ||
| buildEmbeddings, | ||
| cosineSim, | ||
| DEFAULT_MODEL, | ||
| disposeModel, | ||
| EMBEDDING_STRATEGIES, | ||
| embed, | ||
| estimateTokens, | ||
| ftsSearchData, | ||
| hybridSearchData, | ||
| MODELS, | ||
| multiSearchData, | ||
| search, | ||
| searchData, | ||
| } from './embedder.js'; | ||
| // Export (DOT/Mermaid/JSON/GraphML/GraphSON/Neo4j CSV) | ||
| export { | ||
| exportDOT, | ||
| exportGraphML, | ||
| exportGraphSON, | ||
| exportJSON, | ||
| exportMermaid, | ||
| exportNeo4jCSV, | ||
| } from './export.js'; | ||
| // Execution flow tracing | ||
| export { entryPointType, flowData, listEntryPointsData } from './flow.js'; | ||
| // Result formatting | ||
| export { outputResult } from './infrastructure/result-formatter.js'; | ||
| // Test file detection | ||
| export { isTestFile, TEST_PATTERN } from './infrastructure/test-filter.js'; | ||
| // Logger | ||
| export { setVerbose } from './logger.js'; | ||
| // Manifesto rule engine | ||
| export { manifestoData, RULE_DEFS } from './manifesto.js'; | ||
| // Native engine | ||
| export { isNativeAvailable } from './native.js'; | ||
| // Ownership (CODEOWNERS) | ||
| export { matchOwners, ownersData, ownersForFiles, parseCodeowners } from './owners.js'; | ||
| // Pagination utilities | ||
| export { MCP_DEFAULTS, MCP_MAX_LIMIT, paginate, paginateResult, printNdjson } from './paginate.js'; | ||
| // Unified parser API | ||
| export { | ||
| disposeParsers, | ||
| getActiveEngine, | ||
| isWasmAvailable, | ||
| parseFileAuto, | ||
| parseFilesAuto, | ||
| } from './parser.js'; | ||
| // Query functions (data-returning) | ||
| export { | ||
| ALL_SYMBOL_KINDS, | ||
| CORE_EDGE_KINDS, | ||
| CORE_SYMBOL_KINDS, | ||
| childrenData, | ||
| contextData, | ||
| diffImpactData, | ||
| diffImpactMermaid, | ||
| EVERY_EDGE_KIND, | ||
| EVERY_SYMBOL_KIND, | ||
| EXTENDED_SYMBOL_KINDS, | ||
| explainData, | ||
| exportsData, | ||
| FALSE_POSITIVE_CALLER_THRESHOLD, | ||
| FALSE_POSITIVE_NAMES, | ||
| fileDepsData, | ||
| fnDepsData, | ||
| fnImpactData, | ||
| impactAnalysisData, | ||
| iterListFunctions, | ||
| iterRoles, | ||
| iterWhere, | ||
| kindIcon, | ||
| moduleMapData, | ||
| normalizeSymbol, | ||
| pathData, | ||
| queryNameData, | ||
| rolesData, | ||
| STRUCTURAL_EDGE_KINDS, | ||
| statsData, | ||
| VALID_ROLES, | ||
| whereData, | ||
| } from './queries.js'; | ||
| // Query CLI display wrappers | ||
| export { | ||
| children, | ||
| context, | ||
| diffImpact, | ||
| explain, | ||
| fileDeps, | ||
| fileExports, | ||
| fnDeps, | ||
| fnImpact, | ||
| impactAnalysis, | ||
| moduleMap, | ||
| queryName, | ||
| roles, | ||
| stats, | ||
| symbolPath, | ||
| where, | ||
| } from './queries-cli.js'; | ||
| // Registry (multi-repo) | ||
| export { | ||
| listRepos, | ||
| loadRegistry, | ||
| pruneRegistry, | ||
| REGISTRY_PATH, | ||
| registerRepo, | ||
| resolveRepoDbPath, | ||
| saveRegistry, | ||
| unregisterRepo, | ||
| } from './registry.js'; | ||
| // Sequence diagram generation | ||
| export { sequenceData, sequenceToMermaid } from './sequence.js'; | ||
| // Snapshot management | ||
| export { | ||
| snapshotDelete, | ||
| snapshotList, | ||
| snapshotRestore, | ||
| snapshotSave, | ||
| snapshotsDir, | ||
| validateSnapshotName, | ||
| } from './snapshot.js'; | ||
| // Structure analysis | ||
| export { | ||
| buildStructure, | ||
| classifyNodeRoles, | ||
| FRAMEWORK_ENTRY_PREFIXES, | ||
| hotspotsData, | ||
| moduleBoundariesData, | ||
| structureData, | ||
| } from './structure.js'; | ||
| // Triage — composite risk audit | ||
| export { sequenceData } from './sequence.js'; | ||
| export { hotspotsData, moduleBoundariesData, structureData } from './structure.js'; | ||
| export { triageData } from './triage.js'; |
There was a problem hiding this comment.
Section headers don't match their contents
The four section comments create misleading groupings because the exports are ordered alphabetically by source-file name, not by semantic category. Concretely:
// ── Graph Building & Search(line 17) coverscfgData,checkData,coChangeData,communitiesData,complexityData, andloadConfig— none of which are graph-building or search functions; they're query data functions.// ── Constants(line 25) coversfindCycles,dataflowData,buildEmbeddings,hybridSearchData,multiSearchData, andsearchData— onlyEXTENSIONSandIGNORE_DIRSare actually constants.// ── Export Formats(line 30) coversflowData,listEntryPointsData,EVERY_EDGE_KIND,EVERY_SYMBOL_KIND, and all remaining*Data()functions fromqueries.js,sequence.js,structure.js, andtriage.js.
Given that the new file is the authoritative public API surface, consider either grouping semantically (query functions, graph building, export formats, constants, search) or dropping the interior section headers entirely — 55 lines is short enough to read top-to-bottom without them.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
Good catch — the headers were placed by import path order, not semantic grouping. Removed all 4 section headers since the file is short enough to read top-to-bottom without them. Fixed in c15e059.
Summary
src/index.jsfrom ~190 named exports (243 lines) to 48 curated exports (57 lines). Removed CLI formatters, DB internals, parser internals, infrastructure helpers, and implementation-detail constants. All removed exports remain importable via direct paths./clientry point topackage.jsonexports fieldWhat's exported
*Data()query functions (one per command)buildGraph,loadConfig,findCycles,buildEmbeddings)exportDOT,exportJSON,exportMermaid)searchData,multiSearchData,hybridSearchData)EVERY_SYMBOL_KIND,EVERY_EDGE_KIND,EXTENSIONS,IGNORE_DIRS)Test plan
node -e "import('./src/index.js').then(m => console.log(Object.keys(m).length))"→ 48