moodymudskipper / flow

View and Browse Code Using Flow Diagrams
https://moodymudskipper.github.io/flow/
Other
395 stars 26 forks source link

flow_namespaces() #128

Open moodymudskipper opened 1 year ago

moodymudskipper commented 1 year ago

I'd like to see the dependencies between namespaces.

moodymudskipper commented 1 year ago

We can use the promote/demote mechanism here.

We would have the base packages demoted by default, i.e. we don't want to see 15 arrows point to {stats} so we just mention it under the parent package.

Maybe all "no dependency other than base" packages should be demoted by default.

This might be the key to trim some messy trees.

I think the main behavior should be to inspect recursive dependencies (there are already tools but the output doesn't look good AFAICT), if we omit any input we look at the loaded namespaces.

moodymudskipper commented 3 months ago

Here's a draft. if pkg is NULL we consider current development project and read the DESCRIPTION to fetch deps.

I think by default we should hide default packages and demote packages that have no dependency (not including hidden packages). I think this would be enough to make any diagram very clear (no pollution by rlang, cli, glue...). tidyr has a lot of recursive deps and even it would look fine I think.

Probably better from left to right, and right to left for reverse deps

flow_view_package_deps <- function(pkg = NULL, which = "strong", reverse = FALSE) {
  db <- readRDS(url("https://cran.r-project.org/web/packages/packages.rds"))
  if (is.null(pkg)) {
    desc <- read.dcf("DESCRIPTION")
    pkg <- desc[, "Package"]
    desc <- desc[, intersect(colnames(db), colnames(desc)), drop = FALSE]
    more_cols <- setdiff(colnames(db), colnames(desc))
    more_cols <- t(setNames(rep_len(NA, length(more_cols)), more_cols))
    desc <- cbind(desc, more_cols)[,colnames(db), drop = FALSE]
    db <- db[db[, "Package"] != pkg,, drop = FALSE]
    db <- rbind(desc, db)
  }

  deps <- function(pkg) {
    deps_list <- tools::package_dependencies(pkg, db, which, FALSE, reverse, FALSE)
    deps_list <- Filter(length, deps_list)
    deps_df_list <- Map(data.frame, from = names(deps_list), to = deps_list)
    do.call(rbind, deps_df_list)
  } 
  #ptype <- data.frame(pkg = character(), dep = character())p
  deps_df <- function(pkgs) {
    if (is.null(pkgs)) return(NULL)
    df <- deps(pkgs)
    rbind(df, deps_df(setdiff(df$to, df$from)))
  }
  data <- deps_df(pkg)
  # FIXME: better hide or demote
  data <- subset(data, !to %in% c("stats", "graphics", "grDevices", "utils", "datasets", "methods"))

  code <- paste(sprintf("[%s] -> [%s]", data$from, data$to), collapse = "\n")
  out <- flow:::save_nomnoml(code, NULL)
  flow:::as_flow_diagram(out, data, code)
}

flow_view_package_deps("dplyr")

Created on 2024-03-28 with reprex v2.0.2