Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/package/src/common/import-report/deno-info.ts
6456 views
1
/*
2
* deno-info.ts
3
*
4
* functions and interfaces for processing data from `deno info --json`
5
*
6
* Copyright (C) 2022 Posit Software, PBC
7
*
8
*/
9
10
import { architectureToolsPath } from "../../../../src/core/resources.ts";
11
12
////////////////////////////////////////////////////////////////////////////////
13
14
export interface DenoInfoDependency {
15
specifier: string;
16
type?: {
17
error?: string;
18
specifier?: string;
19
span: {
20
start: number;
21
end: number;
22
};
23
};
24
code?: {
25
// apparently, if specifier exists, error doesn't and vice-versa.
26
error?: string;
27
specifier?: string;
28
span: {
29
start: number;
30
end: number;
31
};
32
};
33
}
34
35
export interface DenoInfoModule {
36
dependencies: DenoInfoDependency[];
37
local: string;
38
emit: string;
39
map: unknown;
40
mediaType: string;
41
size: number;
42
specifier: string;
43
}
44
45
export interface DenoInfoJSON {
46
roots: string[];
47
modules: DenoInfoModule[];
48
}
49
50
export type DependencyGraph = Record<string, string[]>;
51
52
export interface ResolutionError {
53
"from": string;
54
to: string; // this is the _unresolved_ specifier
55
message: string;
56
}
57
58
export interface Edge {
59
"from": string;
60
to: string;
61
}
62
63
////////////////////////////////////////////////////////////////////////////////
64
65
export async function getDenoInfo(_root: string): Promise<DenoInfoJSON> {
66
const denoBinary = Deno.env.get("QUARTO_DENO") || architectureToolsPath("deno");
67
const process = Deno.run({
68
cmd: [denoBinary, "info", Deno.args[0], "--json"],
69
stdout: "piped",
70
});
71
const rawOutput = await process.output();
72
73
const json = JSON.parse(new TextDecoder().decode(rawOutput)) as DenoInfoJSON;
74
return json;
75
}
76
77
export function moduleGraph(info: DenoInfoJSON): {
78
graph: DependencyGraph;
79
errors: ResolutionError[];
80
} {
81
const graph: DependencyGraph = {};
82
const errors: ResolutionError[] = [];
83
84
const { modules } = info;
85
for (const { specifier: depFrom, dependencies } of modules) {
86
const edges: string[] = [];
87
for (const { specifier: to, code } of dependencies || []) {
88
const {
89
error,
90
specifier: depTo,
91
} = code || {};
92
if (depTo !== undefined) {
93
edges.push(depTo);
94
} else {
95
errors.push({
96
message: error!,
97
"from": depFrom,
98
to,
99
});
100
}
101
}
102
graph[depFrom] = edges;
103
}
104
105
return { graph, errors };
106
}
107
108
export function graphTranspose(graph: DependencyGraph): DependencyGraph {
109
const result: DependencyGraph = {};
110
for (const node of Object.keys(graph)) {
111
result[node] = [];
112
}
113
for (const [nodeFrom, children] of Object.entries(graph)) {
114
for (const nodeTo of children) {
115
result[nodeTo].push(nodeFrom);
116
}
117
}
118
return result;
119
}
120
121
export function reachability(
122
graph: DependencyGraph,
123
): Record<string, Set<string>> {
124
const result: Record<string, Set<string>> = Object.fromEntries(
125
Object.keys(graph).map((k) => [k, new Set()]),
126
);
127
128
let changed = false;
129
const graphNodes = Object.keys(graph);
130
do {
131
changed = false;
132
for (const node of graphNodes) {
133
for (const child of graph[node]) {
134
for (const nodeDep of result[node]) {
135
changed = changed || !(result[child].has(nodeDep));
136
result[child].add(nodeDep);
137
}
138
changed = changed || !(result[child].has(node));
139
result[child].add(node);
140
}
141
}
142
} while (changed);
143
return result;
144
}
145
146