为了账号安全,请及时绑定邮箱和手机立即绑定

在一个承诺中获取来自不同数组的结果。

在一个承诺中获取来自不同数组的结果。

喵喵时光机 2022-09-29 15:26:27
我正在为盖茨比制作一个自定义源代码插件,它将从GitHub存储库中获取降价文件。存储库具有单个文件(blob)和文件夹(树),它们又包含文件。我需要将所有文件(包括文件夹中的文件)放在一个中,但我不知道如何做到这一点。我已经设法从存储库中获取单个文件,并且我有一个函数,该函数从树中返回一个文件数组。但我不知道如何将它们结合起来。Promise.all这是我的代码。图形 QL 查询以获取存储库、树和文件信息:const repositoryQuery = `{  viewer {    repository(name: "repository-name") {      object(expression: "master:") {        ... on Tree {          entries {            name            oid            type          }        }      }    }  }}`const treeQuery = `  query getTree($id: GitObjectID!) {    viewer {      repository(name: "repository-name") {        object(oid: $id) {          ... on Tree {            entries {              name              oid              type            }          }        }      }    }  }`const fileQuery = `  query getFile($id: GitObjectID!) {    viewer {      repository(name: "repository-name") {        object(oid: $id) {          ... on Blob {            text          }        }      }    }  }` 以及函数本身:const data = await client.request(repositoryQuery)const getTree = async entry => {  const data = await client.request(treeQuery, { id: entry.oid })  const array = await data.viewer.repository.object.entries  return array}const getFile = async entry => {  const data = await client.request(fileQuery, { id: entry.oid })  const result = await data.viewer.repository.object  return result}const files = await Promise.all(  data.viewer.repository.object.entries    .filter(entry => entry.type !== "tree")    .map(entry => {      return (        getFile(entry)        .then(file => {          return {            data: file.text          }        })      )    }  ))files.forEach(file =>  createNode({...}))如何更新,以便:const files运行 ,如果getFile()entry.type !== "tree"如果是 ,则在树中获取一个文件数组,然后为每个文件运行。entry.typetreegetTree()getFile()将所有结果合并到一个数组中,以便我可以应用于它们 。createNode我非常感谢您的帮助。
查看完整描述

2 回答

?
倚天杖

TA贡献1828条经验 获得超3个赞

您可以从用于递归遍历目录的 walk 函数中获得一些灵感。从那里。它看起来像这样:

async function walk(entry, isRoot) {

  if (isRoot){

    return await processEntry(entry);

  }

  let files = await getTreeEntryFromTree(repository, entry.oid);

  files = await Promise.all(files.data.viewer.repository.object.entries.map(async file => {

    return await processEntry(file);

  }));

  return files.reduce((all, folderContents) => all.concat(folderContents), []);

}


async function processEntry(entry){

  if (entry.type === "tree") {

    return walk(entry, false); 

  } else {

    let res = await getBlob(repository, entry.oid);

    return [{

      name: entry.name,

      oid: entry.oid,

      data:res.data.viewer.repository.object.text

    }];

  }

}

因此,它只是将目录替换为树,并在返回文件时请求每个文件的数据内容。


源插件的以下代码(不含 ) :gatsby-node.jscreateSchemaCustomization


const { ApolloClient } = require("apollo-client")

const { InMemoryCache } = require("apollo-cache-inmemory")

const { HttpLink } = require("apollo-link-http")

const fetch = require("node-fetch")

const gql = require("graphql-tag")

const { setContext } = require('apollo-link-context');


const token = "YOUR_TOKEN";

const repository = "YOUR_REPO";


const authLink = setContext((_, { headers }) => {

  return {

    headers: {

      ...headers,

      authorization: token ? `Bearer ${token}` : null,

    }

  }

});


const defaultOptions = {

  watchQuery: {

    fetchPolicy: 'no-cache',

    errorPolicy: 'ignore',

  },

  query: {

    fetchPolicy: 'no-cache',

    errorPolicy: 'all',

  },

}


const client = new ApolloClient({

  link: authLink.concat(new HttpLink({ uri: 'https://api.github.com/graphql', fetch: fetch  })),

  cache: new InMemoryCache(),

  defaultOptions: defaultOptions,

});


exports.sourceNodes = async function sourceNodes(

  {

    actions,

    cache,

    createContentDigest,

    createNodeId,

    getNodesByType,

    getNode,

  },

  pluginOptions

) {

  const { createNode, touchNode, deleteNode } = actions

  const { data } = await getTreeFromRepo(repository)


  let sourceData = data;


  fileArr = []

  sourceData.viewer.repository.object.entries.map(it => {

    fileArr.push(walk(it, true))

  });

  let res = await Promise.all(fileArr)

  let result = res.flat();

  console.log(result);

  console.log(`got ${result.length} results`);

  return

}


async function walk(entry, isRoot) {

  if (isRoot){

    return await processEntry(entry);

  }

  let files = await getTreeEntryFromTree(repository, entry.oid);

  files = await Promise.all(files.data.viewer.repository.object.entries.map(async file => {

    return await processEntry(file);

  }));

  return files.reduce((all, folderContents) => all.concat(folderContents), []);

}


async function processEntry(entry){

  if (entry.type === "tree") {

    return walk(entry, false); 

  } else {

    let res = await getBlob(repository, entry.oid);

    return [{

      name: entry.name,

      oid: entry.oid,

      data:res.data.viewer.repository.object.text

    }];

  }

}


async function getTreeFromRepo(repo) {

    return await client.query({

      query: gql`

        query {

          viewer {

            repository(name: "${repo}") {

              object(expression: "master:") {

                ... on Tree {

                  entries {

                    name

                    oid

                    type

                  }

                }

              }

            }

          }

        }

      `,

    })

}


async function getTreeEntryFromTree(repo, oid) {

  return await client.query({

    query: gql`

      query getTree($id: GitObjectID!) {

        viewer {

          repository(name: "${repo}") {

            object(oid: $id) {

              ... on Tree {

                entries {

                  name

                  oid

                  type

                }

              }

            }

          }

        }

      }

    `,

    variables: {

      id: oid

    }

  })

}


async function getBlob(repo, oid){

  return await client.query({

    query: gql`

      query getFile($id: GitObjectID!) {

        viewer {

          repository(name: "${repo}") {

            object(oid: $id) {

              ... on Blob {

                text

              }

            }

          }

        }

      }

    `,

    variables: {

      id: oid

    }

  })

}

您需要在上面的代码中替换 Github 令牌和存储库名称。


它返回一个包含文件内容、名称和 oid 的对象数组


请注意,使用二进制文件的返回:... on Blob { text }null


文本(字符串)UTF8 文本数据,如果 Blob 是二进制的,则为空


此外,还可以使用 Github API v3 在单个调用中以递归方式遍历树,从而大大减少了请求数。你会有这样的东西:


async function getAllEntries(repo, owner){

  return fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees/master?recursive=1`,{

    headers: {

      'Authorization': `Bearer ${token}`,

    }

  })

  .then(response => response.json());

}

完整示例(对于盖茨比源代码插件):


const { ApolloClient } = require("apollo-client")

const { InMemoryCache } = require("apollo-cache-inmemory")

const { HttpLink } = require("apollo-link-http")

const fetch = require("node-fetch")

const gql = require("graphql-tag")

const { setContext } = require('apollo-link-context');


const token = "YOUR_TOKEN";

const repository = "YOUR_REPO";

const owner = "YOUR_LOGIN";


const authLink = setContext((_, { headers }) => {

  return {

    headers: {

      ...headers,

      authorization: token ? `Bearer ${token}` : null,

    }

  }

});


const defaultOptions = {

  watchQuery: {

    fetchPolicy: 'no-cache',

    errorPolicy: 'ignore',

  },

  query: {

    fetchPolicy: 'no-cache',

    errorPolicy: 'all',

  },

}


const client = new ApolloClient({

  link: authLink.concat(new HttpLink({ uri: 'https://api.github.com/graphql', fetch: fetch  })),

  cache: new InMemoryCache(),

  defaultOptions: defaultOptions,

});


exports.sourceNodes = async function sourceNodes(

  {

    actions,

    cache,

    createContentDigest,

    createNodeId,

    getNodesByType,

    getNode,

  },

  pluginOptions

) {

  const { createNode, touchNode, deleteNode } = actions

  const { tree } = await getAllEntries(repository, owner)

  fileArr = []

  tree.map(it => {

    fileArr.push(walk(it, true))

  });

  let res = await Promise.all(fileArr)

  let result = res.filter(value => Object.keys(value).length !== 0);

  console.log(result);

  console.log(`got ${result.length} results`);

  return

}


async function walk(entry){

  if (entry.type === "blob") {

    let res = await getBlob(repository, entry.sha);

    return {

      name: entry.path,

      oid: entry.sha,

      data: res.data.viewer.repository.object.text

    };

  }

  return {};

}


async function getAllEntries(repo, owner){

  return fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees/master?recursive=1`,{

    headers: {

      'Authorization': `Bearer ${token}`,

    }

  })

  .then(response => response.json());

}


async function getBlob(repo, oid){

  return await client.query({

    query: gql`

      query getFile($id: GitObjectID!) {

        viewer {

          repository(name: "${repo}") {

            object(oid: $id) {

              ... on Blob {

                text

              }

            }

          }

        }

      }

    `,

    variables: {

      id: oid

    }

  })

}

如果您需要不惜一切代价获取二进制内容,则需要使用Github API v3,它直接在获取树结果中提供内容URL。内容 URL 返回以 base64 编码的内容,请参阅此文件。


因此,如果您想要base64编码的内容(二进制+文本),您将拥有以下内容(对于源插件):gatsby-node.js


const fetch = require("node-fetch")


const token = "YOUR_TOKEN";

const repository = "YOUR_REPO";

const owner = "YOUR_LOGIN";


exports.sourceNodes = async function sourceNodes(

  {

    actions,

    cache,

    createContentDigest,

    createNodeId,

    getNodesByType,

    getNode,

  },

  pluginOptions

) {

  const { createNode, touchNode, deleteNode } = actions

  const { tree } = await getAllEntries(repository, owner)

  fileArr = []

  tree.map(it => {

    fileArr.push(walk(it, true))

  });

  let res = await Promise.all(fileArr)

  console.log(res);

  console.log(`got ${res.length} results`);

  return

}


async function walk(entry){

  if (entry.type === "blob") {

    let res = await getBlob(entry.url);

    return {

      name: entry.path,

      oid: entry.sha,

      data: res.content

    };

  }

  return {};

}


async function getAllEntries(repo, owner){

  return fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees/master?recursive=1`, {

    headers: {

      'Authorization': `Bearer ${token}`,

    }

  })

  .then(response => response.json());

}


async function getBlob(url){

  return fetch(url, {

    headers: {

      'Authorization': `Bearer ${token}`,

    }

  })

  .then(response => response.json());

}


查看完整回答
反对 回复 2022-09-29
?
子衿沉夜

TA贡献1828条经验 获得超3个赞

首先,您可以遍历每棵树,然后为每个树获取一个文件数组,这将为您提供一个二维数组:


.map(async entry => {

  const files = await getTree(entry);

  return Promise.all(

    files.map(file => getFile(file).then(fileRes => ({ data: fileRes.text })))

  );

)

然后,您需要拼合结果,使其成为一个单维数组:


const files = allFiles.flat();

我希望我正确地理解了你的问题;结果是一个单维的文件数组(即 ),而不是一个多维数组(即 )。getTree()[file1, file2, file3][[file1, file2], [[file1, file2], [file1]], file1, file2]


查看完整回答
反对 回复 2022-09-29
  • 2 回答
  • 0 关注
  • 84 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号