Path: blob/main/package/src/common/import-report/deno-info.ts
6456 views
/*1* deno-info.ts2*3* functions and interfaces for processing data from `deno info --json`4*5* Copyright (C) 2022 Posit Software, PBC6*7*/89import { architectureToolsPath } from "../../../../src/core/resources.ts";1011////////////////////////////////////////////////////////////////////////////////1213export interface DenoInfoDependency {14specifier: string;15type?: {16error?: string;17specifier?: string;18span: {19start: number;20end: number;21};22};23code?: {24// apparently, if specifier exists, error doesn't and vice-versa.25error?: string;26specifier?: string;27span: {28start: number;29end: number;30};31};32}3334export interface DenoInfoModule {35dependencies: DenoInfoDependency[];36local: string;37emit: string;38map: unknown;39mediaType: string;40size: number;41specifier: string;42}4344export interface DenoInfoJSON {45roots: string[];46modules: DenoInfoModule[];47}4849export type DependencyGraph = Record<string, string[]>;5051export interface ResolutionError {52"from": string;53to: string; // this is the _unresolved_ specifier54message: string;55}5657export interface Edge {58"from": string;59to: string;60}6162////////////////////////////////////////////////////////////////////////////////6364export async function getDenoInfo(_root: string): Promise<DenoInfoJSON> {65const denoBinary = Deno.env.get("QUARTO_DENO") || architectureToolsPath("deno");66const process = Deno.run({67cmd: [denoBinary, "info", Deno.args[0], "--json"],68stdout: "piped",69});70const rawOutput = await process.output();7172const json = JSON.parse(new TextDecoder().decode(rawOutput)) as DenoInfoJSON;73return json;74}7576export function moduleGraph(info: DenoInfoJSON): {77graph: DependencyGraph;78errors: ResolutionError[];79} {80const graph: DependencyGraph = {};81const errors: ResolutionError[] = [];8283const { modules } = info;84for (const { specifier: depFrom, dependencies } of modules) {85const edges: string[] = [];86for (const { specifier: to, code } of dependencies || []) {87const {88error,89specifier: depTo,90} = code || {};91if (depTo !== undefined) {92edges.push(depTo);93} else {94errors.push({95message: error!,96"from": depFrom,97to,98});99}100}101graph[depFrom] = edges;102}103104return { graph, errors };105}106107export function graphTranspose(graph: DependencyGraph): DependencyGraph {108const result: DependencyGraph = {};109for (const node of Object.keys(graph)) {110result[node] = [];111}112for (const [nodeFrom, children] of Object.entries(graph)) {113for (const nodeTo of children) {114result[nodeTo].push(nodeFrom);115}116}117return result;118}119120export function reachability(121graph: DependencyGraph,122): Record<string, Set<string>> {123const result: Record<string, Set<string>> = Object.fromEntries(124Object.keys(graph).map((k) => [k, new Set()]),125);126127let changed = false;128const graphNodes = Object.keys(graph);129do {130changed = false;131for (const node of graphNodes) {132for (const child of graph[node]) {133for (const nodeDep of result[node]) {134changed = changed || !(result[child].has(nodeDep));135result[child].add(nodeDep);136}137changed = changed || !(result[child].has(node));138result[child].add(node);139}140}141} while (changed);142return result;143}144145146