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());
}

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]
添加回答
舉報