spec-up-t 1.0.88 → 1.0.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-up-t",
3
- "version": "1.0.88",
3
+ "version": "1.0.89",
4
4
  "description": "Technical specification drafting tool that generates rich specification documents from markdown. Forked from https://github.com/decentralized-identity/spec-up by Daniel Buchner (https://github.com/csuwildcat)",
5
5
  "main": "./index",
6
6
  "repository": {
@@ -23,9 +23,11 @@
23
23
  },
24
24
  "homepage": "https://github.com/trustoverip/spec-up-t#readme",
25
25
  "dependencies": {
26
+ "@octokit/plugin-throttling": "^9.4.0",
26
27
  "@traptitech/markdown-it-katex": "^3.3.0",
27
28
  "axios": "^1.7.7",
28
29
  "diff": "^7.0.0",
30
+ "dotenv": "^16.4.7",
29
31
  "find-pkg-dir": "^2.0.0",
30
32
  "fs-extra": "^11.2.0",
31
33
  "gulp": "4.0.2",
@@ -52,6 +54,7 @@
52
54
  "markdown-it-textual-uml": "^0.1.3",
53
55
  "markdown-it-toc-and-anchor": "^4.2.0",
54
56
  "merge-stream": "^2.0.0",
57
+ "octokit": "^4.1.0",
55
58
  "pdf-lib": "^1.17.1",
56
59
  "pkg-dir": "^8.0.0",
57
60
  "prismjs": "^1.24.0",
@@ -0,0 +1,46 @@
1
+ const path = require('path');
2
+ const paths = {};
3
+
4
+ // A path can be a directory or a file
5
+ //
6
+ // How to require:
7
+ // const { addPath, getPath, getAllPaths } = require('./config/paths');
8
+ //
9
+ // // Example usage
10
+ // addPath('exampleDir', '/path/to/examplePath');
11
+ // console.log(getPath('examplePath'));
12
+ // console.log(getAllPaths());
13
+
14
+ // Add paths
15
+ paths['output-local-terms'] = path.resolve('output', 'local-terms-dir');
16
+ paths['specsjson'] = path.resolve('specs.json');
17
+
18
+ module.exports = {
19
+ /**
20
+ * Adds a directory or file to the directories object.
21
+ * @param {string} name - The name of the directory.
22
+ * @param {string} dir - The path of the directory.
23
+ */
24
+ addPath: (name, dir) => {
25
+ paths[name] = path.resolve(dir);
26
+ },
27
+ /**
28
+ * Gets the resolved path of a directory or file by its name.
29
+ * @param {string} name - The name of the directory.
30
+ * @returns {string|null} The resolved path of the directory or null if not found.
31
+ */
32
+ getPath: (name) => {
33
+ return paths[name] ? path.resolve(paths[name]) : null;
34
+ },
35
+ /**
36
+ * Gets all directories or files with their resolved paths.
37
+ * @returns {Object} An object containing all directories with their resolved paths.
38
+ */
39
+ getAllPaths: () => {
40
+ const resolvedPaths = {};
41
+ for (const [name, dir] of Object.entries(paths)) {
42
+ resolvedPaths[name] = path.resolve(dir);
43
+ }
44
+ return resolvedPaths;
45
+ },
46
+ };
@@ -19,7 +19,7 @@ function createVersionsIndex(outputPath) {
19
19
  // Directory containing the version files
20
20
  const versionsDir = path.join(outputPath, 'versions');
21
21
 
22
- // Check if the directory exists, if not create it
22
+ // Check if the directory that holds the versions / snapshots exists, if not create it
23
23
  if (!fs.existsSync(versionsDir)) {
24
24
  fs.mkdirSync(versionsDir, { recursive: true });
25
25
  console.log('Directory created:', versionsDir);
@@ -75,10 +75,9 @@ function fixMarkdownFiles(directory) {
75
75
  // Write the modified content back to the file synchronously if there were any changes
76
76
  if (modified) {
77
77
  fs.writeFileSync(itemPath, data, 'utf8');
78
- console.log(`\n SPEC-UP-T: Modified ${item.name}` + "\n");
79
78
  }
80
79
  } catch (err) {
81
- console.error(`\n SPEC-UP-T: Error reading or writing file ${item.name}: ${err}` + "\n");
80
+ console.error(`\n SPEC-UP-T: Error while trying to fix the markdown in file ${item.name}: ${err}` + "\n");
82
81
  }
83
82
  }
84
83
  });
@@ -0,0 +1,17 @@
1
+ // Function to check the rate limit of the GitHub API
2
+ function checkRateLimit(response) {
3
+ const remaining = response.headers.get('X-RateLimit-Remaining');
4
+ const reset = response.headers.get('X-RateLimit-Reset');
5
+
6
+ if (response.status === 403 && remaining === '0') {
7
+ const resetTime = new Date(reset * 1000);
8
+ console.error(`\n SPEC-UP-T: Github API rate limit exceeded. Try again after ${resetTime}. See https://trustoverip.github.io/spec-up-t-website/docs/github-token/ for more info.\n`);
9
+ return true;
10
+ } else if (remaining !== null) {
11
+ console.log(`\n SPEC-UP-T: Github API rate limit: ${remaining} requests remaining. See https://trustoverip.github.io/spec-up-t-website/docs/github-token/ for more info.\n`);
12
+ } else {
13
+ console.warn(`\n SPEC-UP-T: Unable to determine rate limit status. Check your GitHub API token and network connection.\n`);
14
+ }
15
+ return false;
16
+ }
17
+ exports.checkRateLimit = checkRateLimit;
@@ -0,0 +1,23 @@
1
+ function matchTerm(text, term) {
2
+ if (text && typeof text === 'string') {
3
+ const firstLine = text.split('\n')[0].trim();
4
+
5
+ // Check if the string starts with `[[def:` and ends with `]]`
6
+ if (!firstLine.startsWith('[[def:') || !firstLine.endsWith(']]')) {
7
+ console.log('String does not start with `[[def:` or end with `]]`');
8
+ return false;
9
+ }
10
+
11
+ // Remove `[[def:` from the beginning and `]]` from the end
12
+ let relevantPart = firstLine.slice(7, -2);
13
+
14
+ // Split the string on `,` and trim the array elements
15
+ let termsArray = relevantPart.split(',').map(term => term.trim());
16
+
17
+ // Check if the term is in the array
18
+ return termsArray.includes(term);
19
+ } else {
20
+ console.error('Invalid text:', text);
21
+ }
22
+ }
23
+ exports.matchTerm = matchTerm;
@@ -0,0 +1,26 @@
1
+ function matchTerm(text, term) {
2
+ if (!text || typeof text !== 'string') {
3
+ // console.error('Invalid text:', text);
4
+ console.log('Nothing to match');
5
+ return false;
6
+ }
7
+
8
+ const firstLine = text.split('\n')[0].trim();
9
+
10
+ // Check if the string starts with `[[def:` and ends with `]]`
11
+ if (!firstLine.startsWith('[[def:') || !firstLine.endsWith(']]')) {
12
+ console.log('String does not start with `[[def:` or end with `]]`');
13
+ return false;
14
+ }
15
+
16
+ // Remove `[[def:` from the beginning and `]]` from the end
17
+ let relevantPart = firstLine.slice(7, -2);
18
+
19
+ // Split the string on `,` and trim the array elements
20
+ let termsArray = relevantPart.split(',').map(term => term.trim());
21
+
22
+ // Check if the term is in the array
23
+ return termsArray.includes(term);
24
+ }
25
+
26
+ exports.matchTerm = matchTerm;
@@ -0,0 +1,69 @@
1
+ async function searchGitHubCode(GITHUB_API_TOKEN, searchString, owner, repo, subdirectory) {
2
+ const { Octokit } = await import("octokit");
3
+ const { throttling } = await import("@octokit/plugin-throttling");
4
+
5
+ // Create a throttled Octokit instance
6
+ const ThrottledOctokit = Octokit.plugin(throttling);
7
+ const octokit = new ThrottledOctokit({
8
+ auth: GITHUB_API_TOKEN,
9
+ throttle: {
10
+ onRateLimit: (retryAfter, options) => {
11
+ console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
12
+ if (options.request.retryCount <= 1) {
13
+ console.log(`Retrying after ${retryAfter} seconds...`);
14
+ return true;
15
+ }
16
+ },
17
+ onAbuseLimit: (retryAfter, options) => {
18
+ console.warn(`Abuse detected for request ${options.method} ${options.url}`);
19
+ },
20
+ onSecondaryRateLimit: (retryAfter, options) => {
21
+ console.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`);
22
+ if (options.request.retryCount <= 1) {
23
+ console.log(`Retrying after ${retryAfter} seconds...`);
24
+ return true;
25
+ }
26
+ },
27
+ },
28
+ });
29
+
30
+ try {
31
+ // Perform the search using Octokit with exact match
32
+ const searchResponse = await octokit.rest.search.code({
33
+ // q: `${searchString} repo:${owner}/${repo}`, // Fuzzy search
34
+ q: `"${searchString}" repo:${owner}/${repo} path:${subdirectory}`, // Use quotation marks for exact match
35
+ // q: `"${searchString}" repo:${owner}/${repo} case:true`, // DOES NOT WORK Use quotation marks for exact match. Case sensitive search
36
+ });
37
+
38
+ // Log the search results
39
+ console.log("Total results:", searchResponse.data.total_count);
40
+
41
+ // const rateLimitResponse = await octokit.rest.rateLimit.get();
42
+ // console.log("Rate limit:", rateLimitResponse.data);
43
+
44
+ // Fetch the content of each file
45
+ for (const item of searchResponse.data.items) {
46
+ let content = "";
47
+ const fileContentResponse = await octokit.rest.repos.getContent({
48
+ owner: item.repository.owner.login, // Repository owner
49
+ repo: item.repository.name, // Repository name
50
+ path: item.path, // File path
51
+ });
52
+
53
+ // Decode the file content (it's base64-encoded)
54
+ if (fileContentResponse.data.content) {
55
+ content = Buffer.from(fileContentResponse.data.content, "base64").toString("utf-8");
56
+ } else {
57
+ // If the file is larger than 1 MB, GitHub's API will return a download URL instead of the content.
58
+ console.log("File is too large. Download URL:", fileContentResponse.data.download_url);
59
+ }
60
+
61
+ item.content = content;
62
+ }
63
+ return searchResponse;
64
+ } catch (error) {
65
+ console.error("Error searching GitHub or fetching file content:", error);
66
+ }
67
+ }
68
+
69
+ exports.searchGitHubCode = searchGitHubCode;
@@ -0,0 +1,77 @@
1
+ async function searchGitHubCode(GITHUB_API_TOKEN, searchString, owner, repo, subdirectory) {
2
+ const { Octokit } = await import("octokit");
3
+ const { throttling } = await import("@octokit/plugin-throttling");
4
+
5
+ // Create a throttled Octokit instance
6
+ const ThrottledOctokit = Octokit.plugin(throttling);
7
+ const octokit = new ThrottledOctokit({
8
+ auth: GITHUB_API_TOKEN,
9
+ throttle: {
10
+ onRateLimit: (retryAfter, options) => {
11
+ console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
12
+ if (options.request.retryCount <= 1) {
13
+ console.log(`Retrying after ${retryAfter} seconds...`);
14
+ return true;
15
+ }
16
+ },
17
+ onAbuseLimit: (retryAfter, options) => {
18
+ console.warn(`Abuse detected for request ${options.method} ${options.url}`);
19
+ },
20
+ onSecondaryRateLimit: (retryAfter, options) => {
21
+ console.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`);
22
+ if (options.request.retryCount <= 1) {
23
+ console.log(`Retrying after ${retryAfter} seconds...`);
24
+ return true;
25
+ }
26
+ },
27
+ },
28
+ });
29
+
30
+ try {
31
+ // Perform the search using Octokit with exact match
32
+ const searchResponse = await octokit.rest.search.code({
33
+ q: `"${searchString}" repo:${owner}/${repo} path:${subdirectory}`, // Exact match in subdirectory
34
+ });
35
+
36
+ // Log the search results
37
+ console.log("Total results:", searchResponse.data.total_count);
38
+
39
+ // Fetch the content of each file
40
+ for (const item of searchResponse.data.items) {
41
+ // Check if the match is in the first line using text_matches
42
+ const isFirstLineMatch = item.text_matches.some(match =>
43
+ match.fragment.split("\n")[0].includes(searchString)
44
+ );
45
+
46
+ if (!isFirstLineMatch) {
47
+ console.log(`Skipping ${item.path}: Match not in the first line.`);
48
+ continue; // Skip this file
49
+ }
50
+
51
+ // Fetch file content
52
+ let content = "";
53
+ const fileContentResponse = await octokit.rest.repos.getContent({
54
+ owner: item.repository.owner.login, // Repository owner
55
+ repo: item.repository.name, // Repository name
56
+ path: item.path, // File path
57
+ });
58
+
59
+ // Decode the file content (it's base64-encoded)
60
+ if (fileContentResponse.data.content) {
61
+ content = Buffer.from(fileContentResponse.data.content, "base64").toString("utf-8");
62
+ } else {
63
+ // If the file is larger than 1 MB, GitHub's API will return a download URL instead of the content.
64
+ console.log("File is too large. Download URL:", fileContentResponse.data.download_url);
65
+ }
66
+
67
+ // Attach the content to the item
68
+ item.content = content;
69
+ }
70
+
71
+ return searchResponse;
72
+ } catch (error) {
73
+ console.error("Error searching GitHub or fetching file content:", error);
74
+ }
75
+ }
76
+
77
+ exports.searchGitHubCode = searchGitHubCode;
@@ -0,0 +1,85 @@
1
+ async function searchGitHubCode(GITHUB_API_TOKEN, searchString, owner, repo, subdirectory) {
2
+ const { Octokit } = await import("octokit");
3
+ const { throttling } = await import("@octokit/plugin-throttling");
4
+
5
+ // Create a throttled Octokit instance
6
+ const ThrottledOctokit = Octokit.plugin(throttling);
7
+ const octokit = new ThrottledOctokit({
8
+ auth: GITHUB_API_TOKEN,
9
+ throttle: {
10
+ onRateLimit: (retryAfter, options) => {
11
+ console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
12
+ if (options.request.retryCount <= 1) {
13
+ console.log(`Retrying after ${retryAfter} seconds...`);
14
+ return true;
15
+ }
16
+ },
17
+ onAbuseLimit: (retryAfter, options) => {
18
+ console.warn(`Abuse detected for request ${options.method} ${options.url}`);
19
+ },
20
+ onSecondaryRateLimit: (retryAfter, options) => {
21
+ console.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`);
22
+ if (options.request.retryCount <= 1) {
23
+ console.log(`Retrying after ${retryAfter} seconds...`);
24
+ return true;
25
+ }
26
+ },
27
+ },
28
+ });
29
+
30
+ try {
31
+ // Perform the search using Octokit with exact match
32
+ const searchResponse = await octokit.rest.search.code({
33
+ q: `"${searchString}" repo:${owner}/${repo} path:${subdirectory}`, // Exact match in subdirectory
34
+ headers: {
35
+ Accept: "application/vnd.github.v3.text-match+json", // Include text-match media type
36
+ },
37
+ });
38
+
39
+ // Log the search results
40
+ console.log("Total results:", searchResponse.data.total_count);
41
+
42
+ // Fetch the content of each file
43
+ for (const item of searchResponse.data.items) {
44
+ // Check if the match is in the first line using text_matches
45
+ if (!item.text_matches) {
46
+ console.log(`Skipping ${item.path}: No text matches found.`);
47
+ continue;
48
+ }
49
+
50
+ const isFirstLineMatch = item.text_matches.some(match =>
51
+ match.fragment.split("\n")[0].includes(searchString)
52
+ );
53
+
54
+ if (!isFirstLineMatch) {
55
+ console.log(`Skipping ${item.path}: Match not in the first line.`);
56
+ continue; // Skip this file
57
+ }
58
+
59
+ // Fetch file content
60
+ let content = "";
61
+ const fileContentResponse = await octokit.rest.repos.getContent({
62
+ owner: item.repository.owner.login, // Repository owner
63
+ repo: item.repository.name, // Repository name
64
+ path: item.path, // File path
65
+ });
66
+
67
+ // Decode the file content (it's base64-encoded)
68
+ if (fileContentResponse.data.content) {
69
+ content = Buffer.from(fileContentResponse.data.content, "base64").toString("utf-8");
70
+ } else {
71
+ // If the file is larger than 1 MB, GitHub's API will return a download URL instead of the content.
72
+ console.log("File is too large. Download URL:", fileContentResponse.data.download_url);
73
+ }
74
+
75
+ // Attach the content to the item
76
+ item.content = content;
77
+ }
78
+
79
+ return searchResponse;
80
+ } catch (error) {
81
+ console.error("Error searching GitHub or fetching file content:", error);
82
+ }
83
+ }
84
+
85
+ exports.searchGitHubCode = searchGitHubCode;
@@ -0,0 +1,92 @@
1
+ async function searchGitHubCode(GITHUB_API_TOKEN, searchString, owner, repo, subdirectory) {
2
+ const { Octokit } = await import("octokit");
3
+ const { throttling } = await import("@octokit/plugin-throttling");
4
+
5
+ // Create a throttled Octokit instance
6
+ const ThrottledOctokit = Octokit.plugin(throttling);
7
+ const octokit = new ThrottledOctokit({
8
+ auth: GITHUB_API_TOKEN,
9
+ throttle: {
10
+ onRateLimit: (retryAfter, options) => {
11
+ console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
12
+ if (options.request.retryCount <= 1) {
13
+ console.log(`Retrying after ${retryAfter} seconds...`);
14
+ return true;
15
+ }
16
+ },
17
+ onAbuseLimit: (retryAfter, options) => {
18
+ console.warn(`Abuse detected for request ${options.method} ${options.url}`);
19
+ },
20
+ onSecondaryRateLimit: (retryAfter, options) => {
21
+ console.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`);
22
+ if (options.request.retryCount <= 1) {
23
+ console.log(`Retrying after ${retryAfter} seconds...`);
24
+ return true;
25
+ }
26
+ },
27
+ },
28
+ });
29
+
30
+ try {
31
+ // Perform the search using Octokit with exact match
32
+ const searchResponse = await octokit.rest.search.code({
33
+ q: `"${searchString}" repo:${owner}/${repo} path:${subdirectory}`, // Exact match in subdirectory
34
+ headers: {
35
+ Accept: "application/vnd.github.v3.text-match+json", // Include text-match media type
36
+ },
37
+ });
38
+
39
+ // Log the search results
40
+ console.log("Total results:", searchResponse.data.total_count);
41
+
42
+ // Fetch the content of each file
43
+ for (const item of searchResponse.data.items) {
44
+ // Check if text_matches exists and is not empty
45
+ if (!item.text_matches || item.text_matches.length === 0) {
46
+ console.log(`Skipping ${item.path}: No text matches found.`);
47
+ continue;
48
+ }
49
+
50
+ // Check if the match is in the first line using text_matches
51
+ const isFirstLineMatch = item.text_matches.some(match => {
52
+ if (!match.fragment) {
53
+ console.log(`Skipping ${item.path}: No fragment found in text match.`);
54
+ return false;
55
+ }
56
+
57
+ const firstLine = match.fragment.split("\n")[0];
58
+ return firstLine.includes(searchString);
59
+ });
60
+
61
+ if (!isFirstLineMatch) {
62
+ console.log(`Skipping ${item.path}: Match not in the first line.`);
63
+ continue; // Skip this file
64
+ }
65
+
66
+ // Fetch file content
67
+ let content = "";
68
+ const fileContentResponse = await octokit.rest.repos.getContent({
69
+ owner: item.repository.owner.login, // Repository owner
70
+ repo: item.repository.name, // Repository name
71
+ path: item.path, // File path
72
+ });
73
+
74
+ // Decode the file content (it's base64-encoded)
75
+ if (fileContentResponse.data.content) {
76
+ content = Buffer.from(fileContentResponse.data.content, "base64").toString("utf-8");
77
+ } else {
78
+ // If the file is larger than 1 MB, GitHub's API will return a download URL instead of the content.
79
+ console.log("File is too large. Download URL:", fileContentResponse.data.download_url);
80
+ }
81
+
82
+ // Attach the content to the item
83
+ item.content = content;
84
+ }
85
+
86
+ return searchResponse;
87
+ } catch (error) {
88
+ console.error("Error searching GitHub or fetching file content:", error);
89
+ }
90
+ }
91
+
92
+ exports.searchGitHubCode = searchGitHubCode;
@@ -0,0 +1,97 @@
1
+ async function searchGitHubCode(GITHUB_API_TOKEN, searchString, owner, repo, subdirectory) {
2
+ const { Octokit } = await import("octokit");
3
+ const { throttling } = await import("@octokit/plugin-throttling");
4
+
5
+ // Create a throttled Octokit instance
6
+ const ThrottledOctokit = Octokit.plugin(throttling);
7
+ const octokit = new ThrottledOctokit({
8
+ auth: GITHUB_API_TOKEN,
9
+ throttle: {
10
+ onRateLimit: (retryAfter, options) => {
11
+ console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
12
+ if (options.request.retryCount <= 1) {
13
+ console.log(`Retrying after ${retryAfter} seconds...`);
14
+ return true;
15
+ }
16
+ },
17
+ onAbuseLimit: (retryAfter, options) => {
18
+ console.warn(`Abuse detected for request ${options.method} ${options.url}`);
19
+ },
20
+ onSecondaryRateLimit: (retryAfter, options) => {
21
+ console.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`);
22
+ if (options.request.retryCount <= 1) {
23
+ console.log(`Retrying after ${retryAfter} seconds...`);
24
+ return true;
25
+ }
26
+ },
27
+ },
28
+ });
29
+
30
+ try {
31
+ // Perform the search using Octokit with exact match
32
+ const searchResponse = await octokit.rest.search.code({
33
+ q: `"${searchString}" repo:${owner}/${repo} path:${subdirectory}`, // Exact match in subdirectory
34
+ headers: {
35
+ Accept: "application/vnd.github.v3.text-match+json", // Include text-match media type
36
+ },
37
+ });
38
+
39
+ // Log the search results
40
+ console.log("Total results:", searchResponse.data.total_count);
41
+
42
+ // Fetch the content of each file
43
+ for (const item of searchResponse.data.items) {
44
+ // Check if text_matches exists and is not empty
45
+ if (!item.text_matches || item.text_matches.length === 0) {
46
+ console.log(`Skipping ${item.path}: No text matches found.`);
47
+ continue;
48
+ }
49
+
50
+ // Check if the match is in the first line using text_matches
51
+ const isFirstLineMatch = item.text_matches.some(match => {
52
+ if (!match.fragment) {
53
+ console.log(`Skipping ${item.path}: No fragment found in text match.`);
54
+ return false;
55
+ }
56
+
57
+ const firstLine = match.fragment.split("\n")[0];
58
+ return firstLine.includes(searchString);
59
+ });
60
+
61
+ if (!isFirstLineMatch) {
62
+ console.log(`Skipping ${item.path}: Match not in the first line.`);
63
+ continue; // Skip this file
64
+ }
65
+
66
+ // Fetch file content
67
+ let content = "";
68
+ try {
69
+ const fileContentResponse = await octokit.rest.repos.getContent({
70
+ owner: item.repository.owner.login, // Repository owner
71
+ repo: item.repository.name, // Repository name
72
+ path: item.path, // File path
73
+ });
74
+
75
+ // Decode the file content (it's base64-encoded)
76
+ if (fileContentResponse.data.content) {
77
+ content = Buffer.from(fileContentResponse.data.content, "base64").toString("utf-8");
78
+ } else {
79
+ // If the file is larger than 1 MB, GitHub's API will return a download URL instead of the content.
80
+ console.log("File is too large. Download URL:", fileContentResponse.data.download_url);
81
+ }
82
+ } catch (error) {
83
+ console.error(`Error fetching content for ${item.path}:`, error);
84
+ content = ""; // Set content to an empty string if there's an error
85
+ }
86
+
87
+ // Attach the content to the item
88
+ item.content = content;
89
+ }
90
+
91
+ return searchResponse;
92
+ } catch (error) {
93
+ console.error("Error searching GitHub or fetching file content:", error);
94
+ }
95
+ }
96
+
97
+ exports.searchGitHubCode = searchGitHubCode;