spec-up-t 1.0.72 → 1.0.73

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/get-xrefs-data.js +143 -77
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-up-t",
3
- "version": "1.0.72",
3
+ "version": "1.0.73",
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": {
@@ -29,62 +29,84 @@ const outputPathJSON = 'output/xrefs-data.json';
29
29
  const outputPathJS = 'output/xrefs-data.js';
30
30
  const outputPathJSTimeStamped = 'output/xrefs-history/xrefs-data-' + Date.now() + '.js';
31
31
 
32
-
33
- function addAllXrefs(GITHUB_API_TOKEN) {
34
- // Set headers for GitHub API requests. Include an authorization token if provided.
32
+ function setupFetchHeaders(GITHUB_API_TOKEN) {
35
33
  const fetchHeaders = {
36
34
  'Accept': 'application/vnd.github.v3+json'
37
35
  };
38
36
 
39
- // If GITHUB_API_TOKEN is present, it adds an Authorization header to the fetchHeaders object with the value set to token ${GITHUB_API_TOKEN}. This header is used to authenticate requests to the GitHub API, allowing the user to make authenticated requests which have higher rate limits compared to unauthenticated requests.
40
37
  if (GITHUB_API_TOKEN) {
41
38
  fetchHeaders['Authorization'] = `token ${GITHUB_API_TOKEN}`;
42
39
  } else {
43
40
  console.log('\n SPEC-UP-T: There is no GitHub token set up. Therefore, you are more likely to be at your limit of GitHub API requests. If you run into the limit, create a token and search the documentation on this topic.\n');
44
41
  }
45
42
 
46
- // Function to check the rate limit of the GitHub API
47
- function checkRateLimit(response) {
48
- if (response.status === 403 && response.headers.get('X-RateLimit-Remaining') === '0') {
49
- const resetTime = new Date(response.headers.get('X-RateLimit-Reset') * 1000);
50
- console.error(`\n SPEC-UP-T: Github API rate limit exceeded. Try again after ${resetTime}. See https://blockchainbird.github.io/spec-up-t-website/docs/github-token/ for more info.` + "\n");
51
- return true;
52
- } else {
53
- console.log(`\n SPEC-UP-T: Github API rate limit: ${response.headers.get('X-RateLimit-Remaining')} requests remaining. See https://blockchainbird.github.io/spec-up-t-website/docs/github-token/ for more info.` + "\n");
54
- }
55
- return false;
43
+ return fetchHeaders;
44
+ }
45
+
46
+ // Function to check the rate limit of the GitHub API
47
+ function checkRateLimit(response) {
48
+ if (response.status === 403 && response.headers.get('X-RateLimit-Remaining') === '0') {
49
+ const resetTime = new Date(response.headers.get('X-RateLimit-Reset') * 1000);
50
+ console.error(`\n SPEC-UP-T: Github API rate limit exceeded. Try again after ${resetTime}. See https://blockchainbird.github.io/spec-up-t-website/docs/github-token/ for more info.` + "\n");
51
+ return true;
52
+ } else {
53
+ console.log(`\n SPEC-UP-T: Github API rate limit: ${response.headers.get('X-RateLimit-Remaining')} requests remaining. See https://blockchainbird.github.io/spec-up-t-website/docs/github-token/ for more info.` + "\n");
56
54
  }
55
+ return false;
56
+ }
57
57
 
58
- // Function to fetch term information from GitHub, including commit hash and content.
59
- async function fetchTermInfoFromGithub(xref) {
60
- try {
61
- // prerequisite: filename should be the term in the match object with spaces replaced by dashes and all lowercase
62
- //TODO: Loop through all markdown files to find the term and get the filename, instead of assuming that the filename is the term with spaces replaced by dashes and all lowercase
63
- const url = `https://api.github.com/repos/${xref.owner}/${xref.repo}/commits?path=${xref.terms_dir}/${xref.term.replace(/ /g, '-').toLowerCase()}.md&per_page=1`;
64
- const response = await fetch(url, { headers: fetchHeaders });
65
-
66
- // Check for rate limit before proceeding
67
- if (checkRateLimit(response)) {
68
- return;
58
+ // Function to fetch term information from GitHub, including commit hash and content.
59
+ async function fetchTermInfoFromGithub(GITHUB_API_TOKEN, xref) {
60
+ try {
61
+ // prerequisite: filename should be the term in the match object with spaces replaced by dashes and all lowercase
62
+ //TODO: Loop through all markdown files to find the term and get the filename, instead of assuming that the filename is the term with spaces replaced by dashes and all lowercase
63
+ const url = `https://api.github.com/repos/${xref.owner}/${xref.repo}/commits?path=${xref.terms_dir}/${xref.term.replace(/ /g, '-').toLowerCase()}.md&per_page=1`;
64
+ const response = await fetch(url, { headers: setupFetchHeaders(GITHUB_API_TOKEN) });
65
+
66
+ // Check for rate limit before proceeding
67
+ if (checkRateLimit(response)) {
68
+ return;
69
+ }
70
+
71
+ if (response.ok) {
72
+ const data = await response.json();
73
+ if (data.length > 0) {
74
+ const commitHash = data[0].sha;
75
+ const content = await fetchFileContentFromCommit(GITHUB_API_TOKEN, xref.owner, xref.repo, commitHash, `${xref.terms_dir}/${xref.term.replace(/ /g, '-').toLowerCase()}.md`);
76
+ return { commitHash, content };
69
77
  }
78
+ } else {
79
+ console.error(`\n SPEC-UP-T: Failed to fetch commit hash for ${xref.term}: ${response.statusText}\n`);
80
+ return { commitHash: null, content: null };
81
+ }
82
+ } catch (error) {
83
+ console.error(`\n SPEC-UP-T: Error fetching data for term ${xref.term}: ${error.message}\n`);
84
+ }
85
+ return null;
86
+ }
70
87
 
71
- if (response.ok) {
72
- const data = await response.json();
73
- if (data.length > 0) {
74
- const commitHash = data[0].sha;
75
- const content = await fetchFileContentFromCommit(xref.owner, xref.repo, commitHash, `${xref.terms_dir}/${xref.term.replace(/ /g, '-').toLowerCase()}.md`);
76
- return { commitHash, content };
77
- }
78
- } else {
79
- console.error(`\n SPEC-UP-T: Failed to fetch commit hash for ${xref.term}: ${response.statusText}\n`);
80
- return { commitHash: null, content: null };
88
+ // Function to fetch the content of a file from a specific commit in a GitHub repository.
89
+ async function fetchFileContentFromCommit(GITHUB_API_TOKEN, owner, repo, commitHash, filePath) {
90
+ try {
91
+ const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${commitHash}?recursive=1`;
92
+ const treeResponse = await fetch(treeUrl, { headers: setupFetchHeaders(GITHUB_API_TOKEN) });
93
+
94
+ if (treeResponse.ok) {
95
+ const treeData = await treeResponse.json();
96
+ const file = treeData.tree.find(item => item.path === filePath);
97
+ if (file) {
98
+ const fileContentResponse = await fetch(file.url);
99
+ const fileContentData = await fileContentResponse.json();
100
+ return Buffer.from(fileContentData.content, 'base64').toString('utf-8');
81
101
  }
82
- } catch (error) {
83
- console.error(`\n SPEC-UP-T: Error fetching data for term ${xref.term}: ${error.message}\n`);
84
102
  }
85
- return null;
103
+ } catch (error) {
104
+ console.error(`\n SPEC-UP-T: Error fetching file content: ${error.message}\n`);
86
105
  }
106
+ return null;
107
+ }
87
108
 
109
+ function updateXrefs(GITHUB_API_TOKEN) {
88
110
  // Function to extend xref objects with additional information, such as repository URL and directory information.
89
111
  function extendXrefs(config, xrefs) {
90
112
  if (config.specs[0].external_specs_repos) {
@@ -125,56 +147,53 @@ function addAllXrefs(GITHUB_API_TOKEN) {
125
147
  });
126
148
  }
127
149
 
128
- // Function to fetch the content of a file from a specific commit in a GitHub repository.
129
- async function fetchFileContentFromCommit(owner, repo, commitHash, filePath) {
130
- try {
131
- const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${commitHash}?recursive=1`;
132
- const treeResponse = await fetch(treeUrl, { headers: fetchHeaders });
133
-
134
- if (treeResponse.ok) {
135
- const treeData = await treeResponse.json();
136
- const file = treeData.tree.find(item => item.path === filePath);
137
- if (file) {
138
- const fileContentResponse = await fetch(file.url);
139
- const fileContentData = await fileContentResponse.json();
140
- return Buffer.from(fileContentData.content, 'base64').toString('utf-8');
141
- }
142
- }
143
- } catch (error) {
144
- console.error(`\n SPEC-UP-T: Error fetching file content: ${error.message}\n`);
145
- }
146
- return null;
147
- }
148
-
149
- // Initialize an object to store all xrefs. If the output JSON file exists, load its data.
150
+ // Initialize an object to store all xrefs.
150
151
  let allXrefs = { xrefs: [] };
151
152
 
153
+ // If the output JSON file exists, load its data.
152
154
  if (fs.existsSync(outputPathJSON)) {
153
155
  const existingXrefs = fs.readJsonSync(outputPathJSON);
154
156
  allXrefs = existingXrefs && existingXrefs.xrefs ? existingXrefs : { xrefs: [] };
155
157
  }
156
158
 
157
- // Loop through each directory and file, extracting xrefs from markdown files.
159
+ // Function to check if an xref is in the markdown content
160
+ function isXrefInMarkdown(xref, markdownContent) {
161
+ const regex = new RegExp(`\\[\\[xref:${xref.term}\\]\\]`, 'g');
162
+ const result = regex.test(markdownContent);
163
+ return result;
164
+ }
165
+
166
+ // Collect all markdown content
167
+ let allMarkdownContent = '';
168
+
158
169
  specTermsDirectories.forEach(specDirectory => {
159
170
  fs.readdirSync(specDirectory).forEach(file => {
160
171
  if (file.endsWith('.md')) {
161
172
  const markdown = fs.readFileSync(`${specDirectory}/${file}`, 'utf8');
162
- const regex = /\[\[xref:.*?\]\]/g;
163
- if (regex.test(markdown)) {
164
- const xrefs = markdown.match(regex);
165
- xrefs.forEach(xref => {
166
- const newXrefObj = processXref(xref);
167
- if (!allXrefs.xrefs.some(existingXref =>
168
- existingXref.term === newXrefObj.term && existingXref.externalSpec === newXrefObj.externalSpec)) {
169
- allXrefs.xrefs.push(newXrefObj);
170
- }
171
- });
172
- }
173
+ allMarkdownContent += markdown;
173
174
  }
174
175
  });
175
176
  });
176
177
 
177
- // Function to process and clean up xref strings, returning an object with `externalSpec` and `term` properties.
178
+ // Remove existing entries if not in the combined markdown content
179
+ allXrefs.xrefs = allXrefs.xrefs.filter(existingXref => {
180
+ return isXrefInMarkdown(existingXref, allMarkdownContent);
181
+ });
182
+
183
+ // Add new entries if they are in the markdown
184
+ const regex = /\[\[xref:.*?\]\]/g;
185
+ if (regex.test(allMarkdownContent)) {
186
+ const xrefs = allMarkdownContent.match(regex);
187
+ xrefs.forEach(xref => {
188
+ const newXrefObj = processXref(xref);
189
+ if (!allXrefs.xrefs.some(existingXref =>
190
+ existingXref.term === newXrefObj.term && existingXref.externalSpec === newXrefObj.externalSpec)) {
191
+ allXrefs.xrefs.push(newXrefObj);
192
+ }
193
+ });
194
+ };
195
+
196
+ // Function to process and clean up xref strings found in the markdown file, returning an object with `externalSpec` and `term` properties.
178
197
  function processXref(xref) {
179
198
  let [externalSpec, term] = xref.replace(/\[\[xref:/, '').replace(/\]\]/, '').trim().split(/,/, 2);
180
199
  return {
@@ -186,10 +205,16 @@ function addAllXrefs(GITHUB_API_TOKEN) {
186
205
  // Extend each xref with additional data and fetch commit information from GitHub.
187
206
  extendXrefs(config, allXrefs.xrefs);
188
207
 
208
+
209
+ /*
210
+ Function to fetch all term information from GitHub. The function will not fetch the commit hash again if an entry already contains a commit hash.
211
+
212
+ It checks if the xref object already has a commitHash and content.If both are present, it skips fetching the term information from GitHub. This ensures that existing commit hashes are not overwritten.
213
+ */
189
214
  async function fetchAllTermsInfoFromGithub() {
190
215
  for (let xref of allXrefs.xrefs) {
191
216
  if (!xref.commitHash || !xref.content) {
192
- const fetchedData = await fetchTermInfoFromGithub(xref);
217
+ const fetchedData = await fetchTermInfoFromGithub(GITHUB_API_TOKEN, xref);
193
218
  if (fetchedData) {
194
219
  xref.commitHash = fetchedData.commitHash;
195
220
  xref.content = fetchedData.content;
@@ -260,8 +285,49 @@ function removeXref(term, externalSpec) {
260
285
  return messages;
261
286
  }
262
287
 
263
- // Export the addAllXrefs and removeXref functions for use in other modules.
288
+ function addXref(term, externalSpec) {
289
+ let messages = [];
290
+
291
+ try {
292
+ // Read the JSON file
293
+ let currentXrefs = fs.readJsonSync(outputPathJSON);
294
+
295
+ // Check if the term and externalSpec exist
296
+ const entryExists = currentXrefs.xrefs.some(xref => xref.term === term && xref.externalSpec === externalSpec);
297
+
298
+ if (entryExists) {
299
+ messages.push(`\n SPEC-UP-T: Entry with term "${term}" and externalSpec "${externalSpec}" already exists.\n`);
300
+ return messages;
301
+ }
302
+
303
+ // Add the entry to the JSON file
304
+ currentXrefs.xrefs.push({ term, externalSpec });
305
+
306
+ // Convert the JSON object back to a JSON string
307
+ const currentXrefsStr = JSON.stringify(currentXrefs, null, 2);
308
+
309
+ // Write the JSON code to a .json file
310
+ fs.writeFileSync(outputPathJSON, currentXrefsStr, 'utf8');
311
+
312
+ // Create the JS code for the assignment
313
+ const stringReadyForFileWrite = `const allXrefs = ${currentXrefsStr};`;
314
+
315
+ // Write the JS code to a .js file
316
+ fs.writeFileSync(outputPathJS, stringReadyForFileWrite, 'utf8');
317
+
318
+ messages.push(`\n SPEC-UP-T: Entry with term "${term}" and externalSpec "${externalSpec}" added.\n`);
319
+
320
+ // Run the render function to update the HTML file
321
+ require('../index.js')({ nowatch: true });
322
+
323
+ } catch (error) {
324
+ messages.push(`\n SPEC-UP-T: An error occurred - ${error.message}\n`);
325
+ }
326
+ }
327
+
328
+ // Export the updateXrefs and removeXref functions for use in other modules.
264
329
  module.exports = {
265
- addAllXrefs,
266
- removeXref
330
+ updateXrefs,
331
+ removeXref,
332
+ addXref
267
333
  }