@titan-design/code-graph 0.4.0 → 0.5.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/dist/index.d.ts CHANGED
@@ -1206,6 +1206,14 @@ interface CheckViolation {
1206
1206
  threshold?: number;
1207
1207
  destinationId?: string;
1208
1208
  isCarryover?: boolean;
1209
+ /** Repo-relative file the violation sits in; a symbol's parent file. */
1210
+ path?: string;
1211
+ lineStart?: number;
1212
+ lineEnd?: number;
1213
+ symbol?: string;
1214
+ /** One line a reader can check without re-running the rule, such as `loc=412 (max 350)`. */
1215
+ evidence?: string;
1216
+ tool?: string;
1209
1217
  }
1210
1218
  interface CheckResult {
1211
1219
  snapshotId: number;
@@ -1236,6 +1244,34 @@ declare function violationKey(v: CheckViolation): string;
1236
1244
  /** {@link violationKey} with both node ids carried into another snapshot's id space; unmoved ids key as before. */
1237
1245
  declare function rebasedViolationKey(v: CheckViolation, resolve: (id: string) => string): string;
1238
1246
 
1247
+ /** One tool-neutral audit finding; every finding cites a path so a citation checker can verify it. */
1248
+ interface Finding {
1249
+ id: string;
1250
+ path: string;
1251
+ lineStart?: number;
1252
+ lineEnd?: number;
1253
+ symbol?: string;
1254
+ signal: string;
1255
+ value?: number;
1256
+ baseline?: number;
1257
+ threshold?: number;
1258
+ severity: Severity;
1259
+ evidence?: string;
1260
+ tool: string;
1261
+ }
1262
+ /** A diagnostic from an outside linter, shaped structurally so no linter package is imported. */
1263
+ interface ExternalDiagnostic {
1264
+ tool: string;
1265
+ rule: string;
1266
+ file: string;
1267
+ line: number;
1268
+ endLine?: number;
1269
+ message: string;
1270
+ severity: "error" | "warning";
1271
+ }
1272
+ declare function toFindings(result: CheckResult): Finding[];
1273
+ declare function externalToFinding(input: ExternalDiagnostic): Finding;
1274
+
1239
1275
  /** Glob when the pattern has a `*` (`**` crosses directories, `*` stays in a segment); otherwise a case-sensitive substring. */
1240
1276
  declare function patternToRegex(pattern: string): RegExp;
1241
1277
  declare function compilePatterns(patterns: readonly string[] | undefined): RegExp[];
@@ -1552,4 +1588,4 @@ declare function getConventionMap(store: CodeGraphStore, snapshotId: number, mod
1552
1588
  */
1553
1589
  declare function findConventions(store: CodeGraphStore, snapshotId: number, query: string, embedder: Embedder, model: string, opts?: FindConventionsOptions): Promise<ConventionQueryResult>;
1554
1590
 
1555
- export { ALIAS_BASE_ATTR, ALL_ROLES, type AliasChain, type AliasChainInput, type AliasChainOptions, type AliasLoader, type AliasResolution, COMMUNITY_SUMMARY_NAMESPACE, COVERAGE_METRIC_NAME, type CachedEmbedResult, type CheckDiff, type CheckResult, type CheckRule, type CheckRulesFile, type CheckSnapshotOptions, type CheckSnapshotResult, type CheckViolation, CodeGraphStore, type ConventionArea, type ConventionCorpus, type ConventionCoverage, type ConventionMap, type ConventionMatch, type ConventionOptions, type ConventionQueryResult, type ConventionSymbol, DEAD_CODE_METRIC_NAMES, DEFAULT_CHURN_WINDOWS, DOMAIN_DDL, type DeepAst, type DeepAstInput, type DiffCheckResultsOptions, type DiffSnapshotsOptions, type EdgeKind, type EmbedAttempt, type EmbedCoverage, type EmbedSnapshotResult, type EmbeddableSymbol, type FileFingerprint, type FindConventionsOptions, type FindSimilarOptions, type ForbidImportRule, GROWTH_RISK_METRIC_NAMES, type GraphDiff, type GraphDiffSummary, type GraphEdge, type GraphFragment, type GraphMetric, type GraphNode, type HistoryMetricsOptions, INDEX_VERSION, type IdAlias, type IdAliasReason, type IndexOptions, type IndexResult, type IstanbulCoverage, KIT, LanguageExtractor, type LanguageExtractorOptions, type LayeredDepsRule, type LineSpan, type Lineage, type LineageSnapshot, type LineageStep, type LinkMethod, type LinkTestsOptions, type LoadedHistory, METRIC_CATALOGUE, MIGRATIONS, type MemberInfo, type MetricAbsence, type MetricAggregate, type MetricDelta, type MetricDescriptor, type MetricDirection, type MetricMaxRule, type MetricMinRule, type MetricProductMaxRule, type MetricRollup, type MetricSource, type MetricUnit, type NoInternalOnlyBarrelsRule, type NodeKind, type NodeRename, type NodeRole, type PackageFlag, type PackageLayer, type PackageStats, type PageRankOptions, type PageRankResult, type PageRankRow, type PairCoupling, type PairFlag, type ParamInfo, type PartitionQualityInput, type PartitionQualityResult, type PriorSnapshotOptions, type PruneOptions, type PrunePlan, type PruneResult, PythonGraphExtractor, type ReadFile, type ReferenceEdgeLite, type RelevanceOptions, type ResolveAliasOptions, type ReuseBasis, type RuleStore, type RunChecksOptions, SCHEMA_VERSION, SNAPSHOT_SCOPED_TABLES, SOURCE_METRIC_NAMES, SYMBOL_EMBEDDING_NAMESPACE, SYMBOL_ID_SEP, type Severity, type SimilarCandidate, type SimilarResult, type SnapshotInsert, type SnapshotRow, type SnapshotSpec, type SourceLanguage, type SummarizeConventionsResult, type Summarizer, type SymbolConsumers, type SymbolCouplingOptions, type SymbolCouplingPair, type SymbolSpan, type TestCoverageOwnershipOptions, type TestSourceLink, type TopMetricRow, TsMorphGraphExtractor, type TsMorphGraphExtractorOptions, type UnchangedViolation, type ValidateRulesOptions, aggregateMetrics, aliasChain, annotateRoles, attributeCoverage, buildAliases, buildConventionAreas, buildEmbedText, buildFileModuleNodes, buildIndexerMetrics, buildLineage, canonicalEdgeKind, canonicalMetricName, canonicalRole, checkSnapshot, classifyRole, collectDeclaredNames, collectDeclaredSpans, compilePatterns, computeDeadCodeMetrics, computeDeepAst, computeGrowthRiskMetrics, computeMetrics, computePageRank, computePartitionQuality, computeRecencyWindows, computeRelevance, computeRoleHints, computeSourceMetrics, computeSymbolConsumers, computeSymbolCoupling, computeTestCoverageOwnership, createAliasChain, defaultTargetCount, describeMetric, describeMetrics, detectCommunities, detectGitHead, detectGitToplevel, detectRenames, diffCheckResults, diffSnapshots, edgeWeight, embedSnapshot, embedTextsCached, externalId, fileId, findConventions, findSimilarCapability, getConventionMap, getEdgeWeight, groupTestsBySource, hashContent, hashEmbedText, indexPaths, invertBuckets, isGeneratedByHeuristic, isGeneratedFile, isInsideGitRepo, lineagePath, linkTestsToSources, listEdges, listEdgesTouching, listEmbeddableSymbols, listMetrics, listMetricsForNode, listNodes, loadCheckRules, loadGeneratedPatterns, loadHistoryMetrics, loadLineage, matchesAny, moduleId, openCodeGraph, packageId, parentModuleId, parseSymbolId, patternToRegex, planPrune, priorSnapshotForRef, pruneDanglingReferences, readSourceFiles, rebasedViolationKey, resolveAlias, resolveBarrelEdges, resolveChurnWindows, resolveGitRef, resolveSnapshot, runChecks, runPrune, snapshotPageRank, snapshotReferenceEdges, snapshotRelevance, snapshotSymbolConsumers, snapshotSymbolCoupling, snapshotViolations, structuralSignature, summarizeConventions, symbolId, testCoverageCountMetrics, tryEmbedSnapshot, validateRules, violationKey, walkSourceFiles, windowSuffix };
1591
+ export { ALIAS_BASE_ATTR, ALL_ROLES, type AliasChain, type AliasChainInput, type AliasChainOptions, type AliasLoader, type AliasResolution, COMMUNITY_SUMMARY_NAMESPACE, COVERAGE_METRIC_NAME, type CachedEmbedResult, type CheckDiff, type CheckResult, type CheckRule, type CheckRulesFile, type CheckSnapshotOptions, type CheckSnapshotResult, type CheckViolation, CodeGraphStore, type ConventionArea, type ConventionCorpus, type ConventionCoverage, type ConventionMap, type ConventionMatch, type ConventionOptions, type ConventionQueryResult, type ConventionSymbol, DEAD_CODE_METRIC_NAMES, DEFAULT_CHURN_WINDOWS, DOMAIN_DDL, type DeepAst, type DeepAstInput, type DiffCheckResultsOptions, type DiffSnapshotsOptions, type EdgeKind, type EmbedAttempt, type EmbedCoverage, type EmbedSnapshotResult, type EmbeddableSymbol, type ExternalDiagnostic, type FileFingerprint, type FindConventionsOptions, type FindSimilarOptions, type Finding, type ForbidImportRule, GROWTH_RISK_METRIC_NAMES, type GraphDiff, type GraphDiffSummary, type GraphEdge, type GraphFragment, type GraphMetric, type GraphNode, type HistoryMetricsOptions, INDEX_VERSION, type IdAlias, type IdAliasReason, type IndexOptions, type IndexResult, type IstanbulCoverage, KIT, LanguageExtractor, type LanguageExtractorOptions, type LayeredDepsRule, type LineSpan, type Lineage, type LineageSnapshot, type LineageStep, type LinkMethod, type LinkTestsOptions, type LoadedHistory, METRIC_CATALOGUE, MIGRATIONS, type MemberInfo, type MetricAbsence, type MetricAggregate, type MetricDelta, type MetricDescriptor, type MetricDirection, type MetricMaxRule, type MetricMinRule, type MetricProductMaxRule, type MetricRollup, type MetricSource, type MetricUnit, type NoInternalOnlyBarrelsRule, type NodeKind, type NodeRename, type NodeRole, type PackageFlag, type PackageLayer, type PackageStats, type PageRankOptions, type PageRankResult, type PageRankRow, type PairCoupling, type PairFlag, type ParamInfo, type PartitionQualityInput, type PartitionQualityResult, type PriorSnapshotOptions, type PruneOptions, type PrunePlan, type PruneResult, PythonGraphExtractor, type ReadFile, type ReferenceEdgeLite, type RelevanceOptions, type ResolveAliasOptions, type ReuseBasis, type RuleStore, type RunChecksOptions, SCHEMA_VERSION, SNAPSHOT_SCOPED_TABLES, SOURCE_METRIC_NAMES, SYMBOL_EMBEDDING_NAMESPACE, SYMBOL_ID_SEP, type Severity, type SimilarCandidate, type SimilarResult, type SnapshotInsert, type SnapshotRow, type SnapshotSpec, type SourceLanguage, type SummarizeConventionsResult, type Summarizer, type SymbolConsumers, type SymbolCouplingOptions, type SymbolCouplingPair, type SymbolSpan, type TestCoverageOwnershipOptions, type TestSourceLink, type TopMetricRow, TsMorphGraphExtractor, type TsMorphGraphExtractorOptions, type UnchangedViolation, type ValidateRulesOptions, aggregateMetrics, aliasChain, annotateRoles, attributeCoverage, buildAliases, buildConventionAreas, buildEmbedText, buildFileModuleNodes, buildIndexerMetrics, buildLineage, canonicalEdgeKind, canonicalMetricName, canonicalRole, checkSnapshot, classifyRole, collectDeclaredNames, collectDeclaredSpans, compilePatterns, computeDeadCodeMetrics, computeDeepAst, computeGrowthRiskMetrics, computeMetrics, computePageRank, computePartitionQuality, computeRecencyWindows, computeRelevance, computeRoleHints, computeSourceMetrics, computeSymbolConsumers, computeSymbolCoupling, computeTestCoverageOwnership, createAliasChain, defaultTargetCount, describeMetric, describeMetrics, detectCommunities, detectGitHead, detectGitToplevel, detectRenames, diffCheckResults, diffSnapshots, edgeWeight, embedSnapshot, embedTextsCached, externalId, externalToFinding, fileId, findConventions, findSimilarCapability, getConventionMap, getEdgeWeight, groupTestsBySource, hashContent, hashEmbedText, indexPaths, invertBuckets, isGeneratedByHeuristic, isGeneratedFile, isInsideGitRepo, lineagePath, linkTestsToSources, listEdges, listEdgesTouching, listEmbeddableSymbols, listMetrics, listMetricsForNode, listNodes, loadCheckRules, loadGeneratedPatterns, loadHistoryMetrics, loadLineage, matchesAny, moduleId, openCodeGraph, packageId, parentModuleId, parseSymbolId, patternToRegex, planPrune, priorSnapshotForRef, pruneDanglingReferences, readSourceFiles, rebasedViolationKey, resolveAlias, resolveBarrelEdges, resolveChurnWindows, resolveGitRef, resolveSnapshot, runChecks, runPrune, snapshotPageRank, snapshotReferenceEdges, snapshotRelevance, snapshotSymbolConsumers, snapshotSymbolCoupling, snapshotViolations, structuralSignature, summarizeConventions, symbolId, testCoverageCountMetrics, toFindings, tryEmbedSnapshot, validateRules, violationKey, walkSourceFiles, windowSuffix };
package/dist/index.js CHANGED
@@ -4177,11 +4177,13 @@ function describeMetrics(names) {
4177
4177
 
4178
4178
  // src/check/context.ts
4179
4179
  function buildRuleContext(store, snapshotId) {
4180
- const nodes = store.listNodes(snapshotId);
4180
+ const all = store.listNodes(snapshotId, { includeSymbols: true });
4181
+ const nodes = all.filter((n) => n.kind !== "symbol");
4182
+ const symbolNodes2 = all.filter((n) => n.kind === "symbol");
4181
4183
  const edges = store.listEdges(snapshotId);
4182
4184
  const nodesById = /* @__PURE__ */ new Map();
4183
4185
  for (const n of nodes) nodesById.set(n.id, n);
4184
- return { nodes, nodesById, metricsByNode: indexMetrics(store.listMetrics(snapshotId)), edges };
4186
+ return { nodes, symbolNodes: symbolNodes2, nodesById, metricsByNode: indexMetrics(store.listMetrics(snapshotId)), edges };
4185
4187
  }
4186
4188
  function indexMetrics(metrics) {
4187
4189
  const metricsByNode = /* @__PURE__ */ new Map();
@@ -4339,6 +4341,18 @@ function barrelMessage(barrelPkg, importerCount) {
4339
4341
  return importerCount === 0 ? `barrel in package "${barrelPkg}" has no importers` : `barrel in package "${barrelPkg}" has ${importerCount} internal importer(s) but zero external`;
4340
4342
  }
4341
4343
 
4344
+ // src/check/violation-location.ts
4345
+ var CODE_GRAPH_TOOL = "code-graph";
4346
+ function locateNode(node) {
4347
+ if (node.kind !== "symbol") return { path: node.id };
4348
+ const location = { path: node.parentId ?? node.id, symbol: node.name };
4349
+ const startLine = node.attrs?.startLine;
4350
+ const endLine = node.attrs?.endLine;
4351
+ if (typeof startLine === "number") location.lineStart = startLine;
4352
+ if (typeof endLine === "number") location.lineEnd = endLine;
4353
+ return location;
4354
+ }
4355
+
4342
4356
  // src/check/metric-rules.ts
4343
4357
  function nodeFilter(rule) {
4344
4358
  return {
@@ -4353,71 +4367,76 @@ function passesFilter(node, filter) {
4353
4367
  if (node.role && filter.excludedRoles.has(node.role)) return false;
4354
4368
  return true;
4355
4369
  }
4356
- function runMetricMaxRule(rule, ctx) {
4370
+ function candidateNodes(rule, ctx) {
4357
4371
  const filter = nodeFilter(rule);
4372
+ const pool = rule.kind === "symbol" ? ctx.symbolNodes : ctx.nodes;
4373
+ return pool.filter((node) => passesFilter(node, filter));
4374
+ }
4375
+ function toViolation(rule, breach) {
4376
+ return {
4377
+ ruleId: rule.id,
4378
+ severity: severityOf(rule),
4379
+ nodeId: breach.node.id,
4380
+ metric: breach.metric,
4381
+ value: breach.value,
4382
+ threshold: breach.threshold,
4383
+ message: breach.message,
4384
+ ...locateNode(breach.node),
4385
+ evidence: breach.evidence,
4386
+ tool: CODE_GRAPH_TOOL
4387
+ };
4388
+ }
4389
+ function thresholdBreach(node, metric, value, bound, threshold) {
4390
+ const op = bound === "max" ? ">" : "<";
4391
+ return {
4392
+ node,
4393
+ metric,
4394
+ value,
4395
+ threshold,
4396
+ message: `${metric}=${formatNumber(value)} ${op} ${formatNumber(threshold)}`,
4397
+ evidence: `${metric}=${formatNumber(value)} (${bound} ${formatNumber(threshold)})`
4398
+ };
4399
+ }
4400
+ function runMetricMaxRule(rule, ctx) {
4358
4401
  const out = [];
4359
- for (const node of ctx.nodes) {
4360
- if (!passesFilter(node, filter)) continue;
4402
+ for (const node of candidateNodes(rule, ctx)) {
4361
4403
  const value = ctx.metricsByNode.get(node.id)?.get(rule.metric);
4362
- if (value === void 0) continue;
4363
- if (value <= rule.max) continue;
4364
- out.push({
4365
- ruleId: rule.id,
4366
- severity: severityOf(rule),
4367
- nodeId: node.id,
4368
- metric: rule.metric,
4369
- value,
4370
- threshold: rule.max,
4371
- message: `${rule.metric}=${formatNumber(value)} > ${formatNumber(rule.max)}`
4372
- });
4404
+ if (value === void 0 || value <= rule.max) continue;
4405
+ out.push(toViolation(rule, thresholdBreach(node, rule.metric, value, "max", rule.max)));
4373
4406
  }
4374
4407
  return out;
4375
4408
  }
4376
4409
  function runMetricMinRule(rule, ctx) {
4377
- const filter = nodeFilter(rule);
4378
4410
  const out = [];
4379
- for (const node of ctx.nodes) {
4380
- if (!passesFilter(node, filter)) continue;
4411
+ for (const node of candidateNodes(rule, ctx)) {
4381
4412
  const value = ctx.metricsByNode.get(node.id)?.get(rule.metric);
4382
- if (value === void 0) continue;
4383
- if (value >= rule.min) continue;
4384
- out.push({
4385
- ruleId: rule.id,
4386
- severity: severityOf(rule),
4387
- nodeId: node.id,
4388
- metric: rule.metric,
4389
- value,
4390
- threshold: rule.min,
4391
- message: `${rule.metric}=${formatNumber(value)} < ${formatNumber(rule.min)}`
4392
- });
4413
+ if (value === void 0 || value >= rule.min) continue;
4414
+ out.push(toViolation(rule, thresholdBreach(node, rule.metric, value, "min", rule.min)));
4393
4415
  }
4394
4416
  return out;
4395
4417
  }
4396
4418
  function runMetricProductMaxRule(rule, ctx) {
4397
- const filter = nodeFilter(rule);
4398
4419
  const out = [];
4399
- for (const node of ctx.nodes) {
4400
- if (!passesFilter(node, filter)) continue;
4420
+ for (const node of candidateNodes(rule, ctx)) {
4401
4421
  const inner = ctx.metricsByNode.get(node.id);
4402
4422
  if (!inner) continue;
4403
4423
  const components = collectComponents(rule.metrics, inner);
4404
4424
  if (!components) continue;
4405
4425
  const product = components.reduce((a, b) => a * b, 1);
4406
4426
  if (product <= rule.max) continue;
4407
- out.push(productViolation(rule, node.id, components, product));
4427
+ out.push(toViolation(rule, productBreach(rule, node, components, product)));
4408
4428
  }
4409
4429
  return out;
4410
4430
  }
4411
- function productViolation(rule, nodeId, components, product) {
4431
+ function productBreach(rule, node, components, product) {
4412
4432
  const detail = rule.metrics.map((m, i) => `${m}=${formatNumber(components[i])}`).join(" * ");
4413
4433
  return {
4414
- ruleId: rule.id,
4415
- severity: severityOf(rule),
4416
- nodeId,
4434
+ node,
4417
4435
  metric: rule.metrics.join(" * "),
4418
4436
  value: product,
4419
4437
  threshold: rule.max,
4420
- message: `${detail} = ${formatNumber(product)} > ${formatNumber(rule.max)}`
4438
+ message: `${detail} = ${formatNumber(product)} > ${formatNumber(rule.max)}`,
4439
+ evidence: `${detail} = ${formatNumber(product)} (max ${formatNumber(rule.max)})`
4421
4440
  };
4422
4441
  }
4423
4442
  function collectComponents(metrics, values) {
@@ -4507,6 +4526,43 @@ function countByOriginAndSeverity(violations) {
4507
4526
  return counts;
4508
4527
  }
4509
4528
 
4529
+ // src/check/findings.ts
4530
+ function toFindings(result) {
4531
+ return result.violations.map(violationToFinding);
4532
+ }
4533
+ function violationToFinding(v) {
4534
+ const tool = v.tool ?? CODE_GRAPH_TOOL;
4535
+ const target = v.destinationId ? `${v.nodeId}->${v.destinationId}` : v.nodeId;
4536
+ return withoutUndefined({
4537
+ id: `${tool}:${v.ruleId}:${target}`,
4538
+ path: v.path ?? v.nodeId,
4539
+ lineStart: v.lineStart,
4540
+ lineEnd: v.lineEnd,
4541
+ symbol: v.symbol,
4542
+ signal: v.ruleId,
4543
+ value: v.value,
4544
+ threshold: v.threshold,
4545
+ severity: v.severity,
4546
+ evidence: v.evidence ?? v.message,
4547
+ tool
4548
+ });
4549
+ }
4550
+ function externalToFinding(input) {
4551
+ return withoutUndefined({
4552
+ id: `${input.tool}:${input.rule}:${input.file}:${input.line}`,
4553
+ path: input.file,
4554
+ lineStart: input.line,
4555
+ lineEnd: input.endLine,
4556
+ signal: input.rule,
4557
+ severity: input.severity,
4558
+ evidence: input.message,
4559
+ tool: input.tool
4560
+ });
4561
+ }
4562
+ function withoutUndefined(finding) {
4563
+ return Object.fromEntries(Object.entries(finding).filter(([, v]) => v !== void 0));
4564
+ }
4565
+
4510
4566
  // src/check/validate.ts
4511
4567
  function validateRules(input, options = {}) {
4512
4568
  if (!input || typeof input !== "object") {
@@ -5414,6 +5470,7 @@ export {
5414
5470
  embedSnapshot,
5415
5471
  embedTextsCached,
5416
5472
  externalId,
5473
+ externalToFinding,
5417
5474
  fileId,
5418
5475
  findConventions,
5419
5476
  findSimilarCapability,
@@ -5472,6 +5529,7 @@ export {
5472
5529
  summarizeConventions,
5473
5530
  symbolId,
5474
5531
  testCoverageCountMetrics,
5532
+ toFindings,
5475
5533
  tryEmbedSnapshot,
5476
5534
  validateRules,
5477
5535
  violationKey,