@dbt-tools/core 0.3.2

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 (37) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +51 -0
  3. package/dist/analysis/analysis-snapshot.d.ts +145 -0
  4. package/dist/analysis/analysis-snapshot.js +615 -0
  5. package/dist/analysis/dependency-service.d.ts +56 -0
  6. package/dist/analysis/dependency-service.js +75 -0
  7. package/dist/analysis/execution-analyzer.d.ts +85 -0
  8. package/dist/analysis/execution-analyzer.js +245 -0
  9. package/dist/analysis/manifest-graph.d.ts +118 -0
  10. package/dist/analysis/manifest-graph.js +651 -0
  11. package/dist/analysis/run-results-search.d.ts +56 -0
  12. package/dist/analysis/run-results-search.js +127 -0
  13. package/dist/analysis/sql-analyzer.d.ts +30 -0
  14. package/dist/analysis/sql-analyzer.js +218 -0
  15. package/dist/browser.d.ts +11 -0
  16. package/dist/browser.js +17 -0
  17. package/dist/errors/error-handler.d.ts +26 -0
  18. package/dist/errors/error-handler.js +59 -0
  19. package/dist/formatting/field-filter.d.ts +29 -0
  20. package/dist/formatting/field-filter.js +112 -0
  21. package/dist/formatting/graph-export.d.ts +9 -0
  22. package/dist/formatting/graph-export.js +147 -0
  23. package/dist/formatting/output-formatter.d.ts +77 -0
  24. package/dist/formatting/output-formatter.js +160 -0
  25. package/dist/index.d.ts +15 -0
  26. package/dist/index.js +38 -0
  27. package/dist/introspection/schema-generator.d.ts +29 -0
  28. package/dist/introspection/schema-generator.js +275 -0
  29. package/dist/io/artifact-loader.d.ts +27 -0
  30. package/dist/io/artifact-loader.js +142 -0
  31. package/dist/types.d.ts +43 -0
  32. package/dist/types.js +2 -0
  33. package/dist/validation/input-validator.d.ts +39 -0
  34. package/dist/validation/input-validator.js +167 -0
  35. package/dist/version.d.ts +28 -0
  36. package/dist/version.js +60 -0
  37. package/package.json +47 -0
@@ -0,0 +1,615 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAnalysisSnapshotFromParsedArtifacts = buildAnalysisSnapshotFromParsedArtifacts;
4
+ exports.buildAnalysisSnapshotFromArtifacts = buildAnalysisSnapshotFromArtifacts;
5
+ const run_results_search_1 = require("./run-results-search");
6
+ const execution_analyzer_1 = require("./execution-analyzer");
7
+ const manifest_graph_1 = require("./manifest-graph");
8
+ const RESOURCE_TYPE_ORDER = [
9
+ "model",
10
+ "source",
11
+ "test",
12
+ "metric",
13
+ "semantic_model",
14
+ "exposure",
15
+ "seed",
16
+ "snapshot",
17
+ "unit_test",
18
+ "analysis",
19
+ "macro",
20
+ ];
21
+ function now() {
22
+ return performance.now();
23
+ }
24
+ function statusTone(status) {
25
+ const normalized = status === null || status === void 0 ? void 0 : status.trim().toLowerCase();
26
+ if (!normalized)
27
+ return "neutral";
28
+ if (["success", "pass", "passed"].includes(normalized)) {
29
+ return "positive";
30
+ }
31
+ if (["warn", "warning"].includes(normalized)) {
32
+ return "warning";
33
+ }
34
+ if (["error", "fail", "failed", "run error"].includes(normalized)) {
35
+ return "danger";
36
+ }
37
+ return "neutral";
38
+ }
39
+ function statusLabel(status) {
40
+ if (!status)
41
+ return "Unknown";
42
+ return status
43
+ .split(/[\s_-]+/)
44
+ .filter(Boolean)
45
+ .map((part) => part[0].toUpperCase() + part.slice(1).toLowerCase())
46
+ .join(" ");
47
+ }
48
+ function inferPackageNameFromUniqueId(uniqueId) {
49
+ var _a;
50
+ const parts = uniqueId.split(".");
51
+ if (parts.length < 2)
52
+ return "";
53
+ return (_a = parts[1]) !== null && _a !== void 0 ? _a : "";
54
+ }
55
+ function inferResourceTypeFromId(uniqueId) {
56
+ var _a;
57
+ const prefix = (_a = uniqueId.split(".")[0]) !== null && _a !== void 0 ? _a : "";
58
+ const known = new Set([
59
+ "model",
60
+ "test",
61
+ "unit_test",
62
+ "seed",
63
+ "snapshot",
64
+ "source",
65
+ "source_freshness",
66
+ "exposure",
67
+ "metric",
68
+ "semantic_model",
69
+ "analysis",
70
+ "macro",
71
+ ]);
72
+ return known.has(prefix) ? prefix : "operation";
73
+ }
74
+ function resourceTypeLabel(resourceType) {
75
+ return resourceType
76
+ .split("_")
77
+ .map((part) => part[0].toUpperCase() + part.slice(1))
78
+ .join(" ");
79
+ }
80
+ function normalizeStringArray(value) {
81
+ return Array.isArray(value)
82
+ ? value.filter((entry) => typeof entry === "string")
83
+ : [];
84
+ }
85
+ function buildMetricDefinition(attributes) {
86
+ const primaryMeasure = typeof attributes.metric_measure === "string"
87
+ ? attributes.metric_measure
88
+ : null;
89
+ const measures = normalizeStringArray(attributes.metric_input_measures);
90
+ return {
91
+ kind: "metric",
92
+ label: typeof attributes.label === "string" ? attributes.label : null,
93
+ description: typeof attributes.description === "string"
94
+ ? attributes.description
95
+ : null,
96
+ metricType: typeof attributes.metric_type === "string"
97
+ ? attributes.metric_type
98
+ : null,
99
+ expression: typeof attributes.metric_expression === "string"
100
+ ? attributes.metric_expression
101
+ : null,
102
+ sourceReference: typeof attributes.metric_source_reference === "string"
103
+ ? attributes.metric_source_reference
104
+ : typeof attributes.metric_measure === "string"
105
+ ? attributes.metric_measure
106
+ : null,
107
+ filters: normalizeStringArray(attributes.metric_filters),
108
+ timeGranularity: typeof attributes.metric_time_granularity === "string"
109
+ ? attributes.metric_time_granularity
110
+ : null,
111
+ measures: measures.length > 0
112
+ ? measures
113
+ : primaryMeasure != null
114
+ ? [primaryMeasure]
115
+ : [],
116
+ metrics: normalizeStringArray(attributes.metric_input_metrics),
117
+ };
118
+ }
119
+ function buildSemanticModelDefinition(attributes) {
120
+ return {
121
+ kind: "semantic_model",
122
+ label: typeof attributes.label === "string" ? attributes.label : null,
123
+ description: typeof attributes.description === "string"
124
+ ? attributes.description
125
+ : null,
126
+ sourceReference: typeof attributes.semantic_model_reference === "string"
127
+ ? attributes.semantic_model_reference
128
+ : null,
129
+ defaultTimeDimension: typeof attributes.semantic_model_default_time_dimension === "string"
130
+ ? attributes.semantic_model_default_time_dimension
131
+ : null,
132
+ entities: normalizeStringArray(attributes.semantic_model_entities),
133
+ measures: normalizeStringArray(attributes.semantic_model_measures),
134
+ dimensions: normalizeStringArray(attributes.semantic_model_dimensions),
135
+ };
136
+ }
137
+ function buildResourceDefinition(resourceType, attributes) {
138
+ if (resourceType === "metric") {
139
+ return buildMetricDefinition(attributes);
140
+ }
141
+ if (resourceType === "semantic_model") {
142
+ return buildSemanticModelDefinition(attributes);
143
+ }
144
+ return null;
145
+ }
146
+ function sortByResourceType(a, b) {
147
+ const aIndex = RESOURCE_TYPE_ORDER.indexOf(a);
148
+ const bIndex = RESOURCE_TYPE_ORDER.indexOf(b);
149
+ if (aIndex === -1 && bIndex === -1)
150
+ return a.localeCompare(b);
151
+ if (aIndex === -1)
152
+ return 1;
153
+ if (bIndex === -1)
154
+ return -1;
155
+ return aIndex - bIndex;
156
+ }
157
+ function sortResources(a, b) {
158
+ const typeOrder = sortByResourceType(a.resourceType, b.resourceType);
159
+ if (typeOrder !== 0)
160
+ return typeOrder;
161
+ return a.name.localeCompare(b.name);
162
+ }
163
+ function buildResourcesAndDependencyIndex(graph, executionById) {
164
+ const resources = [];
165
+ const dependencyIndex = {};
166
+ const graphologyGraph = graph.getGraph();
167
+ graphologyGraph.forEachNode((uniqueId, attributes) => {
168
+ const execution = executionById.get(uniqueId);
169
+ resources.push({
170
+ uniqueId,
171
+ name: String(attributes.name || uniqueId),
172
+ resourceType: String(attributes.resource_type || "unknown"),
173
+ packageName: String(attributes.package_name || ""),
174
+ path: typeof attributes.path === "string" ? attributes.path : null,
175
+ originalFilePath: typeof attributes.original_file_path === "string"
176
+ ? attributes.original_file_path
177
+ : null,
178
+ patchPath: typeof attributes.patch_path === "string"
179
+ ? attributes.patch_path
180
+ : null,
181
+ database: typeof attributes.database === "string" ? attributes.database : null,
182
+ schema: typeof attributes.schema === "string" ? attributes.schema : null,
183
+ description: typeof attributes.description === "string"
184
+ ? attributes.description
185
+ : null,
186
+ compiledCode: typeof attributes.compiled_code === "string"
187
+ ? attributes.compiled_code
188
+ : null,
189
+ rawCode: typeof attributes.raw_code === "string" ? attributes.raw_code : null,
190
+ definition: buildResourceDefinition(String(attributes.resource_type || "unknown"), attributes),
191
+ status: (execution === null || execution === void 0 ? void 0 : execution.status) ? statusLabel(execution.status) : null,
192
+ statusTone: statusTone(execution === null || execution === void 0 ? void 0 : execution.status),
193
+ executionTime: typeof (execution === null || execution === void 0 ? void 0 : execution.execution_time) === "number"
194
+ ? execution.execution_time
195
+ : null,
196
+ threadId: typeof (execution === null || execution === void 0 ? void 0 : execution.thread_id) === "string" ? execution.thread_id : null,
197
+ });
198
+ const upstream = graph.getUpstream(uniqueId);
199
+ const downstream = graph.getDownstream(uniqueId);
200
+ dependencyIndex[uniqueId] = {
201
+ upstreamCount: upstream.length,
202
+ downstreamCount: downstream.length,
203
+ upstream: upstream.slice(0, 8).map((entry) => {
204
+ const attrs = graphologyGraph.getNodeAttributes(entry.nodeId);
205
+ return {
206
+ uniqueId: entry.nodeId,
207
+ name: String((attrs === null || attrs === void 0 ? void 0 : attrs.name) || entry.nodeId),
208
+ resourceType: String((attrs === null || attrs === void 0 ? void 0 : attrs.resource_type) || "unknown"),
209
+ depth: entry.depth,
210
+ };
211
+ }),
212
+ downstream: downstream.slice(0, 8).map((entry) => {
213
+ const attrs = graphologyGraph.getNodeAttributes(entry.nodeId);
214
+ return {
215
+ uniqueId: entry.nodeId,
216
+ name: String((attrs === null || attrs === void 0 ? void 0 : attrs.name) || entry.nodeId),
217
+ resourceType: String((attrs === null || attrs === void 0 ? void 0 : attrs.resource_type) || "unknown"),
218
+ depth: entry.depth,
219
+ };
220
+ }),
221
+ };
222
+ });
223
+ resources.sort(sortResources);
224
+ return { resources, dependencyIndex };
225
+ }
226
+ function buildResourceGroups(resources) {
227
+ var _a;
228
+ const groupedResources = new Map();
229
+ for (const resource of resources) {
230
+ const current = (_a = groupedResources.get(resource.resourceType)) !== null && _a !== void 0 ? _a : [];
231
+ current.push(resource);
232
+ groupedResources.set(resource.resourceType, current);
233
+ }
234
+ return [...groupedResources.entries()]
235
+ .sort(([a], [b]) => sortByResourceType(a, b))
236
+ .map(([resourceType, grouped]) => ({
237
+ resourceType,
238
+ label: resourceTypeLabel(resourceType),
239
+ count: grouped.length,
240
+ attentionCount: grouped.filter((r) => r.statusTone === "danger" || r.statusTone === "warning").length,
241
+ resources: grouped,
242
+ }));
243
+ }
244
+ function buildManifestEntryLookup(manifestJson) {
245
+ const lookup = new Map();
246
+ const addEntries = (value) => {
247
+ if (value == null || typeof value !== "object")
248
+ return;
249
+ for (const [key, entry] of Object.entries(value)) {
250
+ if (entry != null && typeof entry === "object") {
251
+ lookup.set(key, entry);
252
+ }
253
+ }
254
+ };
255
+ addEntries(manifestJson.nodes);
256
+ addEntries(manifestJson.sources);
257
+ addEntries(manifestJson.unit_tests);
258
+ if (manifestJson.disabled != null &&
259
+ typeof manifestJson.disabled === "object") {
260
+ for (const [key, entries] of Object.entries(manifestJson.disabled)) {
261
+ if (!Array.isArray(entries))
262
+ continue;
263
+ for (const entry of entries) {
264
+ if (entry != null && typeof entry === "object") {
265
+ lookup.set(key, entry);
266
+ }
267
+ }
268
+ }
269
+ }
270
+ return lookup;
271
+ }
272
+ function getManifestAttrs(uniqueId, graphologyGraph, manifestEntryLookup) {
273
+ if (graphologyGraph.hasNode(uniqueId)) {
274
+ return graphologyGraph.getNodeAttributes(uniqueId);
275
+ }
276
+ return manifestEntryLookup.get(uniqueId);
277
+ }
278
+ function resolveTestParentFromManifest(graph, graphologyGraph, manifestEntryLookup, testUniqueId) {
279
+ var _a, _b;
280
+ const upstream = graph.getUpstream(testUniqueId);
281
+ const direct = upstream.filter((u) => u.depth === 1);
282
+ const candidates = direct.length > 0 ? direct : upstream;
283
+ for (const u of candidates) {
284
+ const uAttrs = getManifestAttrs(u.nodeId, graphologyGraph, manifestEntryLookup);
285
+ const uType = String((_a = uAttrs === null || uAttrs === void 0 ? void 0 : uAttrs.resource_type) !== null && _a !== void 0 ? _a : "");
286
+ if (uType !== "test" && uType !== "unit_test" && uType !== "") {
287
+ return u.nodeId;
288
+ }
289
+ }
290
+ const testAttrs = manifestEntryLookup.get(testUniqueId);
291
+ const attachedNode = typeof (testAttrs === null || testAttrs === void 0 ? void 0 : testAttrs.attached_node) === "string"
292
+ ? testAttrs.attached_node
293
+ : null;
294
+ if (attachedNode != null) {
295
+ return attachedNode;
296
+ }
297
+ const dependsOn = testAttrs === null || testAttrs === void 0 ? void 0 : testAttrs.depends_on;
298
+ if (Array.isArray(dependsOn === null || dependsOn === void 0 ? void 0 : dependsOn.nodes)) {
299
+ for (const parentId of dependsOn.nodes) {
300
+ if (typeof parentId !== "string")
301
+ continue;
302
+ const parentAttrs = getManifestAttrs(parentId, graphologyGraph, manifestEntryLookup);
303
+ const parentType = String((_b = parentAttrs === null || parentAttrs === void 0 ? void 0 : parentAttrs.resource_type) !== null && _b !== void 0 ? _b : inferResourceTypeFromId(parentId));
304
+ if (parentType !== "test" && parentType !== "unit_test") {
305
+ return parentId;
306
+ }
307
+ }
308
+ }
309
+ return null;
310
+ }
311
+ function manifestDisplayPath(attrs) {
312
+ if (typeof (attrs === null || attrs === void 0 ? void 0 : attrs.original_file_path) === "string") {
313
+ return attrs.original_file_path;
314
+ }
315
+ if (typeof (attrs === null || attrs === void 0 ? void 0 : attrs.path) === "string") {
316
+ return attrs.path;
317
+ }
318
+ return null;
319
+ }
320
+ function enrichGanttItemRow(item, graph, graphologyGraph, manifestEntryLookup) {
321
+ const attrs = getManifestAttrs(item.unique_id, graphologyGraph, manifestEntryLookup);
322
+ const rtRaw = attrs === null || attrs === void 0 ? void 0 : attrs.resource_type;
323
+ const resourceType = typeof rtRaw === "string" && rtRaw
324
+ ? rtRaw
325
+ : inferResourceTypeFromId(item.unique_id);
326
+ const parentId = resourceType === "test" || resourceType === "unit_test"
327
+ ? resolveTestParentFromManifest(graph, graphologyGraph, manifestEntryLookup, item.unique_id)
328
+ : null;
329
+ const pkg = typeof (attrs === null || attrs === void 0 ? void 0 : attrs.package_name) === "string" && attrs.package_name.length > 0
330
+ ? attrs.package_name
331
+ : inferPackageNameFromUniqueId(item.unique_id);
332
+ const mat = attrs === null || attrs === void 0 ? void 0 : attrs.materialized;
333
+ const materialized = typeof mat === "string" && mat.trim() !== "" ? mat : null;
334
+ return Object.assign(Object.assign({}, item), { resourceType, packageName: pkg, path: manifestDisplayPath(attrs), parentId,
335
+ materialized });
336
+ }
337
+ function statusSeverity(status) {
338
+ const normalized = status === null || status === void 0 ? void 0 : status.trim().toLowerCase();
339
+ if (!normalized)
340
+ return 0;
341
+ if (["error", "fail", "failed", "run error"].includes(normalized)) {
342
+ return 3;
343
+ }
344
+ if (["warn", "warning"].includes(normalized)) {
345
+ return 2;
346
+ }
347
+ if (["success", "pass", "passed"].includes(normalized)) {
348
+ return 1;
349
+ }
350
+ return 0;
351
+ }
352
+ function pickRepresentativeStatus(items) {
353
+ var _a, _b;
354
+ let bestStatus = (_b = (_a = items[0]) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : "unknown";
355
+ let bestSeverity = statusSeverity(bestStatus);
356
+ for (const item of items.slice(1)) {
357
+ const severity = statusSeverity(item.status);
358
+ if (severity > bestSeverity) {
359
+ bestSeverity = severity;
360
+ bestStatus = item.status;
361
+ }
362
+ }
363
+ return bestStatus;
364
+ }
365
+ function compareGanttItems(a, b) {
366
+ const startDiff = a.start - b.start;
367
+ if (startDiff !== 0)
368
+ return startDiff;
369
+ const durationDiff = b.duration - a.duration;
370
+ if (durationDiff !== 0)
371
+ return durationDiff;
372
+ return a.name.localeCompare(b.name);
373
+ }
374
+ function buildSyntheticSourceRows(enrichedGanttData, graphologyGraph) {
375
+ var _a, _b;
376
+ const existingIds = new Set(enrichedGanttData.map((item) => item.unique_id));
377
+ const testsBySourceId = new Map();
378
+ for (const item of enrichedGanttData) {
379
+ if ((item.resourceType !== "test" && item.resourceType !== "unit_test") ||
380
+ item.parentId == null ||
381
+ !graphologyGraph.hasNode(item.parentId)) {
382
+ continue;
383
+ }
384
+ const parentAttrs = graphologyGraph.getNodeAttributes(item.parentId);
385
+ if (String((_a = parentAttrs === null || parentAttrs === void 0 ? void 0 : parentAttrs.resource_type) !== null && _a !== void 0 ? _a : "") !== "source") {
386
+ continue;
387
+ }
388
+ const existing = (_b = testsBySourceId.get(item.parentId)) !== null && _b !== void 0 ? _b : [];
389
+ existing.push(item);
390
+ testsBySourceId.set(item.parentId, existing);
391
+ }
392
+ const syntheticRows = [];
393
+ for (const [sourceId, tests] of testsBySourceId.entries()) {
394
+ if (existingIds.has(sourceId) || tests.length === 0) {
395
+ continue;
396
+ }
397
+ const sourceAttrs = graphologyGraph.getNodeAttributes(sourceId);
398
+ const sortedTests = [...tests].sort(compareGanttItems);
399
+ const start = Math.min(...sortedTests.map((item) => item.start));
400
+ const end = Math.max(...sortedTests.map((item) => item.end));
401
+ syntheticRows.push({
402
+ unique_id: sourceId,
403
+ name: typeof (sourceAttrs === null || sourceAttrs === void 0 ? void 0 : sourceAttrs.name) === "string" && sourceAttrs.name.length > 0
404
+ ? sourceAttrs.name
405
+ : sourceId,
406
+ start,
407
+ end,
408
+ duration: Math.max(0, end - start),
409
+ status: pickRepresentativeStatus(sortedTests),
410
+ resourceType: "source",
411
+ packageName: typeof (sourceAttrs === null || sourceAttrs === void 0 ? void 0 : sourceAttrs.package_name) === "string" &&
412
+ sourceAttrs.package_name.length > 0
413
+ ? sourceAttrs.package_name
414
+ : inferPackageNameFromUniqueId(sourceId),
415
+ path: manifestDisplayPath(sourceAttrs),
416
+ parentId: null,
417
+ compileStart: null,
418
+ compileEnd: null,
419
+ executeStart: null,
420
+ executeEnd: null,
421
+ materialized: null,
422
+ });
423
+ }
424
+ return syntheticRows.sort(compareGanttItems);
425
+ }
426
+ function buildStatusBreakdown(summary, nodeExecutions) {
427
+ var _a, _b;
428
+ const durationByStatus = new Map();
429
+ for (const execution of nodeExecutions) {
430
+ const status = statusLabel(execution.status);
431
+ durationByStatus.set(status, ((_a = durationByStatus.get(status)) !== null && _a !== void 0 ? _a : 0) + ((_b = execution.execution_time) !== null && _b !== void 0 ? _b : 0));
432
+ }
433
+ return Object.entries(summary.nodes_by_status)
434
+ .map(([status, count]) => {
435
+ var _a;
436
+ return ({
437
+ status: statusLabel(status),
438
+ count,
439
+ duration: (_a = durationByStatus.get(statusLabel(status))) !== null && _a !== void 0 ? _a : 0,
440
+ share: summary.total_nodes > 0 ? count / summary.total_nodes : 0,
441
+ tone: statusTone(status),
442
+ });
443
+ })
444
+ .sort((a, b) => b.count - a.count);
445
+ }
446
+ function buildTimelineAdjacency(graphologyGraph, executedUniqueIds) {
447
+ const out = {};
448
+ for (const id of executedUniqueIds) {
449
+ out[id] = graphologyGraph.hasNode(id)
450
+ ? {
451
+ inbound: [...graphologyGraph.inboundNeighbors(id)],
452
+ outbound: [...graphologyGraph.outboundNeighbors(id)],
453
+ }
454
+ : { inbound: [], outbound: [] };
455
+ }
456
+ return out;
457
+ }
458
+ function buildThreadStats(executions) {
459
+ var _a, _b;
460
+ const threadAggregation = new Map();
461
+ for (const execution of executions) {
462
+ const threadId = (_a = execution.threadId) !== null && _a !== void 0 ? _a : "unknown";
463
+ const current = (_b = threadAggregation.get(threadId)) !== null && _b !== void 0 ? _b : {
464
+ count: 0,
465
+ totalExecutionTime: 0,
466
+ };
467
+ current.count += 1;
468
+ current.totalExecutionTime += execution.executionTime;
469
+ threadAggregation.set(threadId, current);
470
+ }
471
+ return [...threadAggregation.entries()]
472
+ .map(([threadId, value]) => ({
473
+ threadId,
474
+ count: value.count,
475
+ totalExecutionTime: value.totalExecutionTime,
476
+ }))
477
+ .sort((a, b) => b.totalExecutionTime - a.totalExecutionTime);
478
+ }
479
+ function buildProjectName(manifestJson) {
480
+ const metaMaybe = manifestJson.metadata;
481
+ if (metaMaybe !== null &&
482
+ typeof metaMaybe === "object" &&
483
+ "project_name" in metaMaybe &&
484
+ typeof metaMaybe.project_name === "string" &&
485
+ metaMaybe.project_name !== "") {
486
+ return metaMaybe.project_name;
487
+ }
488
+ return null;
489
+ }
490
+ function buildInvocationId(runResultsJson) {
491
+ const metadata = runResultsJson.metadata != null &&
492
+ typeof runResultsJson.metadata === "object"
493
+ ? runResultsJson.metadata
494
+ : null;
495
+ return typeof (metadata === null || metadata === void 0 ? void 0 : metadata.invocation_id) === "string"
496
+ ? metadata.invocation_id
497
+ : null;
498
+ }
499
+ function buildWarehouseType(manifestJson) {
500
+ const metaMaybe = manifestJson.metadata;
501
+ if (metaMaybe !== null &&
502
+ typeof metaMaybe === "object" &&
503
+ "adapter_type" in metaMaybe &&
504
+ typeof metaMaybe.adapter_type === "string" &&
505
+ metaMaybe.adapter_type !== "") {
506
+ return metaMaybe.adapter_type;
507
+ }
508
+ return null;
509
+ }
510
+ function buildAnalysisSnapshotFromParsedArtifacts(manifestJson, runResultsJson, manifest, runResults) {
511
+ var _a, _b, _c, _d;
512
+ const graphStart = now();
513
+ const graph = new manifest_graph_1.ManifestGraph(manifest);
514
+ const analyzer = new execution_analyzer_1.ExecutionAnalyzer(runResults, graph);
515
+ const graphBuildMs = now() - graphStart;
516
+ const snapshotStart = now();
517
+ const projectName = buildProjectName(manifestJson);
518
+ const warehouseType = buildWarehouseType(manifestJson);
519
+ const summary = analyzer.getSummary();
520
+ const manifestEntryLookup = buildManifestEntryLookup(manifestJson);
521
+ const ganttData = analyzer.getGanttData();
522
+ const nodeExecutions = analyzer.getNodeExecutions();
523
+ const startTimestamps = nodeExecutions
524
+ .map((e) => (e.started_at ? new Date(e.started_at).getTime() : null))
525
+ .filter((t) => t !== null);
526
+ const runStartedAt = startTimestamps.length > 0 ? Math.min(...startTimestamps) : null;
527
+ const bottlenecks = (0, run_results_search_1.detectBottlenecks)(summary.node_executions, {
528
+ mode: "top_n",
529
+ top: 5,
530
+ graph,
531
+ });
532
+ const graphSummary = graph.getSummary();
533
+ const ganttById = new Map(ganttData.map((item) => [item.unique_id, item]));
534
+ const executionById = new Map(nodeExecutions.map((e) => [e.unique_id, e]));
535
+ const { resources, dependencyIndex } = buildResourcesAndDependencyIndex(graph, executionById);
536
+ const graphologyGraph = graph.getGraph();
537
+ const enrichedGanttData = ganttData.map((item) => enrichGanttItemRow(item, graph, graphologyGraph, manifestEntryLookup));
538
+ const syntheticSourceRows = buildSyntheticSourceRows(enrichedGanttData, graphologyGraph);
539
+ const timelineGanttData = [...enrichedGanttData, ...syntheticSourceRows].sort(compareGanttItems);
540
+ const timelineAdjacency = buildTimelineAdjacency(graphologyGraph, timelineGanttData.map((g) => g.unique_id));
541
+ const executions = nodeExecutions
542
+ .map((execution) => {
543
+ var _a, _b, _c;
544
+ const attrs = graphologyGraph.hasNode(execution.unique_id)
545
+ ? graphologyGraph.getNodeAttributes(execution.unique_id)
546
+ : undefined;
547
+ const gantt = ganttById.get(execution.unique_id);
548
+ return {
549
+ uniqueId: execution.unique_id,
550
+ name: String((attrs === null || attrs === void 0 ? void 0 : attrs.name) || execution.unique_id),
551
+ resourceType: String((attrs === null || attrs === void 0 ? void 0 : attrs.resource_type) || inferResourceTypeFromId(execution.unique_id)),
552
+ packageName: (() => {
553
+ const pkg = attrs === null || attrs === void 0 ? void 0 : attrs.package_name;
554
+ if (typeof pkg === "string" && pkg.length > 0)
555
+ return pkg;
556
+ return inferPackageNameFromUniqueId(execution.unique_id);
557
+ })(),
558
+ path: typeof (attrs === null || attrs === void 0 ? void 0 : attrs.original_file_path) === "string"
559
+ ? attrs.original_file_path
560
+ : typeof (attrs === null || attrs === void 0 ? void 0 : attrs.path) === "string"
561
+ ? attrs.path
562
+ : null,
563
+ status: statusLabel(execution.status),
564
+ statusTone: statusTone(execution.status),
565
+ executionTime: (_a = execution.execution_time) !== null && _a !== void 0 ? _a : 0,
566
+ threadId: typeof execution.thread_id === "string" ? execution.thread_id : null,
567
+ start: (_b = gantt === null || gantt === void 0 ? void 0 : gantt.start) !== null && _b !== void 0 ? _b : null,
568
+ end: (_c = gantt === null || gantt === void 0 ? void 0 : gantt.end) !== null && _c !== void 0 ? _c : null,
569
+ };
570
+ })
571
+ .sort((a, b) => b.executionTime - a.executionTime);
572
+ const resourceGroups = buildResourceGroups(resources);
573
+ const statusBreakdown = buildStatusBreakdown(summary, nodeExecutions);
574
+ const threadStats = buildThreadStats(executions);
575
+ const selectedResourceId = (_d = (_b = (_a = resources.find((r) => r.resourceType === "model")) === null || _a === void 0 ? void 0 : _a.uniqueId) !== null && _b !== void 0 ? _b : (_c = resources[0]) === null || _c === void 0 ? void 0 : _c.uniqueId) !== null && _d !== void 0 ? _d : null;
576
+ const analysis = {
577
+ summary,
578
+ projectName,
579
+ warehouseType,
580
+ runStartedAt,
581
+ ganttData: timelineGanttData,
582
+ bottlenecks,
583
+ graphSummary: {
584
+ totalNodes: graphSummary.total_nodes,
585
+ totalEdges: graphSummary.total_edges,
586
+ hasCycles: graphSummary.has_cycles,
587
+ nodesByType: graphSummary.nodes_by_type,
588
+ },
589
+ resources,
590
+ resourceGroups,
591
+ executions,
592
+ statusBreakdown,
593
+ threadStats,
594
+ dependencyIndex,
595
+ timelineAdjacency,
596
+ selectedResourceId,
597
+ invocationId: buildInvocationId(runResultsJson),
598
+ };
599
+ return {
600
+ analysis,
601
+ timings: {
602
+ graphBuildMs,
603
+ snapshotBuildMs: now() - snapshotStart,
604
+ },
605
+ };
606
+ }
607
+ async function buildAnalysisSnapshotFromArtifacts(manifestJson, runResultsJson) {
608
+ const [{ parseManifest }, { parseRunResults }] = await Promise.all([
609
+ import("dbt-artifacts-parser/manifest"),
610
+ import("dbt-artifacts-parser/run_results"),
611
+ ]);
612
+ const manifest = parseManifest(manifestJson);
613
+ const runResults = parseRunResults(runResultsJson);
614
+ return buildAnalysisSnapshotFromParsedArtifacts(manifestJson, runResultsJson, manifest, runResults).analysis;
615
+ }
@@ -0,0 +1,56 @@
1
+ import type { ManifestGraph } from "./manifest-graph";
2
+ /**
3
+ * Dependency analysis result (flat format)
4
+ */
5
+ export interface DependencyResult {
6
+ resource_id: string;
7
+ direction: "upstream" | "downstream";
8
+ build_order?: boolean;
9
+ dependencies: Array<{
10
+ unique_id: string;
11
+ resource_type: string;
12
+ name: string;
13
+ package_name: string;
14
+ depth: number;
15
+ [key: string]: unknown;
16
+ }>;
17
+ count: number;
18
+ }
19
+ /**
20
+ * Nested dependency node for tree format
21
+ */
22
+ export interface DependencyTreeNode {
23
+ unique_id: string;
24
+ resource_type: string;
25
+ name: string;
26
+ package_name: string;
27
+ depth: number;
28
+ dependencies: DependencyTreeNode[];
29
+ [key: string]: unknown;
30
+ }
31
+ /**
32
+ * Dependency result in tree format
33
+ */
34
+ export interface DependencyResultTree {
35
+ resource_id: string;
36
+ direction: "upstream" | "downstream";
37
+ dependencies: DependencyTreeNode[];
38
+ count: number;
39
+ }
40
+ /**
41
+ * DependencyService wraps ManifestGraph dependency methods with formatting
42
+ * and field filtering capabilities.
43
+ */
44
+ export declare class DependencyService {
45
+ /**
46
+ * Get dependencies for a resource with optional field filtering, depth limit, output format, and build order.
47
+ * @param depth - Optional max traversal depth; 1 = immediate neighbors, undefined = all levels
48
+ * @param format - Output structure: flat list or nested tree
49
+ * @param buildOrder - When true and direction is upstream, return dependencies in topological build order
50
+ */
51
+ static getDependencies(graph: ManifestGraph, resourceId: string, direction: "upstream" | "downstream", fields?: string, depth?: number, format?: "flat" | "tree", buildOrder?: boolean): DependencyResult | DependencyResultTree;
52
+ /**
53
+ * Build nested tree from BFS entries with parent tracking
54
+ */
55
+ private static getDependenciesTree;
56
+ }