倚天杖
您可以从用于递归遍历目录的 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.jscreateSchemaCustomizationconst { 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.jsconst 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());}