首页 > 解决方案 > 使用递归 Elixir 获取 npm 包的所有依赖项

问题描述

@registry "http://registry.npmjs.org/"当您附加包名称时,我有这个 url /latest ,它会返回有关包的一些详细信息,我需要获取我所做的所有依赖项并且它工作正常,但我需要更深入地了解它。如。

如果您检查http://registry.npmjs.org/handlebars/latest它并且它有 4 个依赖项,并且我想要这些deps以及进一步使用这些neo-async以及其他depsdeps这些deps以获取它们的依赖项是什么。我试过这个。

defmodule Deep do
  @registry "http://registry.npmjs.org/"

  alias HTTPoison.Response, as: Resp

  def go(package, complete_deps \\ []) do
    HTTPoison.get(@registry <> package <> "/latest")
    |> handle_response()
    |> get_deps()
  end

  defp get_deps(nil),  do: []
  defp get_deps(deps),  do: Enum.map(deps, fn({k, _v}) -> k end)

  defp handle_response({:ok, %Resp{status_code: 200, body: body}}), do:
    Poison.decode!(body)["dependencies"]
  defp handle_response(_), do: nil
end

但我最终还是在第一级,我试过了

get_deps 结果做 head 和 tail,与 deps 一起走得更远,但我不知道在哪里可以保存 tail 或所有 deps。

基本上,我想使用递归在一个列表中获取车把、deps 及其所有 deps 的 deps,我可以看到 Enum.map 的解决方案,但它会有点难看。任何帮助将不胜感激

标签: elixir

解决方案


以下代码将构建依赖关系树。

它依赖于jasonElixir 包并使用httpcErlang 标准库中提供的 HTTP 客户端。使用这些与使用poisonhttpoison具有将代码依赖项的数量从8降低到1的优势:

defmodule Deep do
  @registry 'http://registry.npmjs.org/'

  def go([]), do: []
  def go([dep | other_deps]), do: [go(dep) | go(other_deps)]
  def go(package) do
    deps =
      [@registry, to_charlist(package), '/latest']
      |> :httpc.request()
      |> handle_response()
      |> get_deps()

    if Enum.empty?(deps), do: package, else: {package, go(deps)}
  end

  defp get_deps(nil), do: []
  defp get_deps(deps), do: Map.keys(deps)

  defp handle_response({:ok, {{_, 200, _}, _headers, body}}),
    do: Jason.decode!(body)["dependencies"]

  defp handle_response(_), do: nil
end

输出:

iex(1)> Deep.go("handlebars")
{"handlebars",
 [
   "neo-async",
   {"optimist", ["minimist", "wordwrap"]},
   "source-map",
   {"uglify-js", ["commander", "source-map"]}
 ]}
iex(2)>

推荐阅读