spec-up-t 1.0.80 → 1.0.82
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/assets/compiled/body.js +14 -6
- package/assets/compiled/head.css +1 -1
- package/assets/css/index.css +44 -2
- package/assets/js/css-helper.js +30 -0
- package/assets/js/show-commit-hashes.js +113 -21
- package/index.js +22 -15
- package/package.json +1 -1
- package/src/asset-map.json +3 -1
- package/src/create-pdf.js +28 -0
- package/src/fix-markdown-files.js +1 -1
- package/src/{get-xrefs-data.js → get-xtrefs-data.js} +61 -61
- package/src/prepare-tref.js +96 -0
- package/templates/template.html +1 -1
|
@@ -24,15 +24,15 @@ if (!fs.existsSync('output')) {
|
|
|
24
24
|
fs.mkdirSync('output');
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
// Ensure that the 'output/
|
|
28
|
-
if (!fs.existsSync('output/
|
|
29
|
-
fs.mkdirSync('output/
|
|
27
|
+
// Ensure that the 'output/xtrefs-history' directory exists, creating it if necessary.
|
|
28
|
+
if (!fs.existsSync('output/xtrefs-history')) {
|
|
29
|
+
fs.mkdirSync('output/xtrefs-history');
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// Define paths for various output files, including JSON and JS files.
|
|
33
|
-
const outputPathJSON = 'output/
|
|
34
|
-
const outputPathJS = 'output/
|
|
35
|
-
const outputPathJSTimeStamped = 'output/
|
|
33
|
+
const outputPathJSON = 'output/xtrefs-data.json';
|
|
34
|
+
const outputPathJS = 'output/xtrefs-data.js';
|
|
35
|
+
const outputPathJSTimeStamped = 'output/xtrefs-history/xtrefs-data-' + Date.now() + '.js';
|
|
36
36
|
|
|
37
37
|
function setupFetchHeaders(GITHUB_API_TOKEN) {
|
|
38
38
|
const fetchHeaders = {
|
|
@@ -61,11 +61,11 @@ function checkRateLimit(response) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// Function to fetch term information from GitHub, including commit hash and content.
|
|
64
|
-
async function fetchTermInfoFromGithub(GITHUB_API_TOKEN,
|
|
64
|
+
async function fetchTermInfoFromGithub(GITHUB_API_TOKEN, xtref) {
|
|
65
65
|
try {
|
|
66
66
|
// prerequisite: filename should be the term in the match object with spaces replaced by dashes and all lowercase
|
|
67
67
|
//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
|
|
68
|
-
const url = `https://api.github.com/repos/${
|
|
68
|
+
const url = `https://api.github.com/repos/${xtref.owner}/${xtref.repo}/commits?path=${xtref.terms_dir}/${xtref.term.replace(/ /g, '-').toLowerCase()}.md&per_page=1`;
|
|
69
69
|
const response = await fetch(url, { headers: setupFetchHeaders(GITHUB_API_TOKEN) });
|
|
70
70
|
|
|
71
71
|
// Check for rate limit before proceeding
|
|
@@ -77,15 +77,15 @@ async function fetchTermInfoFromGithub(GITHUB_API_TOKEN, xref) {
|
|
|
77
77
|
const data = await response.json();
|
|
78
78
|
if (data.length > 0) {
|
|
79
79
|
const commitHash = data[0].sha;
|
|
80
|
-
const content = await fetchFileContentFromCommit(GITHUB_API_TOKEN,
|
|
80
|
+
const content = await fetchFileContentFromCommit(GITHUB_API_TOKEN, xtref.owner, xtref.repo, commitHash, `${xtref.terms_dir}/${xtref.term.replace(/ /g, '-').toLowerCase()}.md`);
|
|
81
81
|
return { commitHash, content };
|
|
82
82
|
}
|
|
83
83
|
} else {
|
|
84
|
-
console.error(`\n SPEC-UP-T: Failed to fetch commit hash for ${
|
|
84
|
+
console.error(`\n SPEC-UP-T: Failed to fetch commit hash for ${xtref.term}: ${response.statusText}\n`);
|
|
85
85
|
return { commitHash: null, content: null };
|
|
86
86
|
}
|
|
87
87
|
} catch (error) {
|
|
88
|
-
console.error(`\n SPEC-UP-T: Error fetching data for term ${
|
|
88
|
+
console.error(`\n SPEC-UP-T: Error fetching data for term ${xtref.term}: ${error.message}\n`);
|
|
89
89
|
}
|
|
90
90
|
return null;
|
|
91
91
|
}
|
|
@@ -133,40 +133,40 @@ async function fetchFileContentFromCommit(GITHUB_API_TOKEN, owner, repo, commitH
|
|
|
133
133
|
return null;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
function
|
|
137
|
-
// Function to extend
|
|
138
|
-
function
|
|
136
|
+
function updateXTrefs(GITHUB_API_TOKEN, skipExisting) {
|
|
137
|
+
// Function to extend xtref objects with additional information, such as repository URL and directory information.
|
|
138
|
+
function extendXTrefs(config, xtrefs) {
|
|
139
139
|
if (config.specs[0].external_specs_repos) {
|
|
140
140
|
console.log("\n SPEC-UP-T: PLEASE NOTE: Your specs.json file is outdated (not your fault, we changed something). Use this one: https://github.com/trustoverip/spec-up-t-starter-pack/blob/main/spec-up-t-starterpack/specs.json or e-mail kor@dwarshuis.com for help. \n");
|
|
141
141
|
return;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
xtrefs.forEach(xtref => {
|
|
145
145
|
config.specs.forEach(spec => {
|
|
146
|
-
// Loop through "external_specs" to find the repository URL for each
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
146
|
+
// Loop through "external_specs" to find the repository URL for each xtref
|
|
147
|
+
xtref.repoUrl = null;
|
|
148
|
+
xtref.terms_dir = null;
|
|
149
|
+
xtref.owner = null;
|
|
150
|
+
xtref.repo = null;
|
|
151
151
|
|
|
152
152
|
spec.external_specs.forEach(repo => {
|
|
153
|
-
if (repo.external_spec ===
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const urlParts = new URL(
|
|
157
|
-
|
|
158
|
-
|
|
153
|
+
if (repo.external_spec === xtref.externalSpec) {
|
|
154
|
+
xtref.repoUrl = repo.url;
|
|
155
|
+
xtref.terms_dir = repo.terms_dir;
|
|
156
|
+
const urlParts = new URL(xtref.repoUrl).pathname.split('/');
|
|
157
|
+
xtref.owner = urlParts[1];
|
|
158
|
+
xtref.repo = urlParts[2];
|
|
159
159
|
}
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
-
// Loop through "external_specs" to find the site URL for each
|
|
162
|
+
// Loop through "external_specs" to find the site URL for each xtref
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
xtref.site = null;
|
|
165
165
|
if (spec.external_specs) {
|
|
166
166
|
spec.external_specs.forEach(externalSpec => {
|
|
167
167
|
const key = Object.keys(externalSpec)[0];
|
|
168
|
-
if (key ===
|
|
169
|
-
|
|
168
|
+
if (key === xtref.externalSpec) {
|
|
169
|
+
xtref.site = externalSpec[key];
|
|
170
170
|
}
|
|
171
171
|
});
|
|
172
172
|
}
|
|
@@ -174,18 +174,19 @@ function updateXrefs(GITHUB_API_TOKEN, skipExisting) {
|
|
|
174
174
|
});
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
// Initialize an object to store all
|
|
178
|
-
let
|
|
177
|
+
// Initialize an object to store all xtrefs.
|
|
178
|
+
let allXTrefs = { xtrefs: [] };
|
|
179
179
|
|
|
180
180
|
// If the output JSON file exists, load its data.
|
|
181
181
|
if (fs.existsSync(outputPathJSON)) {
|
|
182
|
-
const
|
|
183
|
-
|
|
182
|
+
const existingXTrefs = fs.readJsonSync(outputPathJSON);
|
|
183
|
+
allXTrefs = existingXTrefs && existingXTrefs.xtrefs ? existingXTrefs : { xtrefs: [] };
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
// Function to check if an
|
|
187
|
-
function
|
|
188
|
-
const regex = new RegExp(`\\[\\[xref:${xref.term}\\]\\]`, 'g');
|
|
186
|
+
// Function to check if an xtref is in the markdown content
|
|
187
|
+
function isXTrefInMarkdown(xtref, markdownContent) {
|
|
188
|
+
// const regex = new RegExp(`\\[\\[xref:${xref.term}\\]\\]`, 'g');
|
|
189
|
+
const regex = new RegExp(`\\[\\[(?:x|t)ref:${xtref.term}\\]\\]`, 'g');
|
|
189
190
|
const result = regex.test(markdownContent);
|
|
190
191
|
return result;
|
|
191
192
|
}
|
|
@@ -203,26 +204,26 @@ function updateXrefs(GITHUB_API_TOKEN, skipExisting) {
|
|
|
203
204
|
});
|
|
204
205
|
|
|
205
206
|
// Remove existing entries if not in the combined markdown content
|
|
206
|
-
|
|
207
|
-
return
|
|
207
|
+
allXTrefs.xtrefs = allXTrefs.xtrefs.filter(existingXTref => {
|
|
208
|
+
return isXTrefInMarkdown(existingXTref, allMarkdownContent);
|
|
208
209
|
});
|
|
209
210
|
|
|
210
211
|
// Add new entries if they are in the markdown
|
|
211
|
-
const regex = /\[\[xref:.*?\]\]/g;
|
|
212
|
+
const regex = /\[\[(?:xref|tref):.*?\]\]/g;
|
|
212
213
|
if (regex.test(allMarkdownContent)) {
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
if (!
|
|
217
|
-
|
|
218
|
-
|
|
214
|
+
const xtrefs = allMarkdownContent.match(regex);
|
|
215
|
+
xtrefs.forEach(xtref => {
|
|
216
|
+
const newXTrefObj = processXTref(xtref);
|
|
217
|
+
if (!allXTrefs.xtrefs.some(existingXTref =>
|
|
218
|
+
existingXTref.term === newXTrefObj.term && existingXTref.externalSpec === newXTrefObj.externalSpec)) {
|
|
219
|
+
allXTrefs.xtrefs.push(newXTrefObj);
|
|
219
220
|
}
|
|
220
221
|
});
|
|
221
222
|
};
|
|
222
223
|
|
|
223
|
-
// Function to process and clean up xref strings found in the markdown file, returning an object with `externalSpec` and `term` properties.
|
|
224
|
-
function
|
|
225
|
-
let [externalSpec, term] =
|
|
224
|
+
// Function to process and clean up xref / tref strings found in the markdown file, returning an object with `externalSpec` and `term` properties.
|
|
225
|
+
function processXTref(xtref) {
|
|
226
|
+
let [externalSpec, term] = xtref.replace(/\[\[(?:xref|tref):/, '').replace(/\]\]/, '').trim().split(/,/, 2);
|
|
226
227
|
return {
|
|
227
228
|
externalSpec: externalSpec.trim(),
|
|
228
229
|
term: term.trim()
|
|
@@ -230,30 +231,30 @@ function updateXrefs(GITHUB_API_TOKEN, skipExisting) {
|
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
// Extend each xref with additional data and fetch commit information from GitHub.
|
|
233
|
-
|
|
234
|
+
extendXTrefs(config, allXTrefs.xtrefs);
|
|
234
235
|
|
|
235
236
|
|
|
236
237
|
/*
|
|
237
238
|
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.
|
|
238
239
|
|
|
239
|
-
It checks if the
|
|
240
|
+
It checks if the xtref 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.
|
|
240
241
|
*/
|
|
241
242
|
async function fetchAllTermsInfoFromGithub(skipExisting) {
|
|
242
|
-
for (let
|
|
243
|
-
if (!skipExisting || (!
|
|
244
|
-
const fetchedData = await fetchTermInfoFromGithub(GITHUB_API_TOKEN,
|
|
243
|
+
for (let xtref of allXTrefs.xtrefs) {
|
|
244
|
+
if (!skipExisting || (!xtref.commitHash || !xtref.content)) {
|
|
245
|
+
const fetchedData = await fetchTermInfoFromGithub(GITHUB_API_TOKEN, xtref);
|
|
245
246
|
if (fetchedData) {
|
|
246
|
-
|
|
247
|
-
|
|
247
|
+
xtref.commitHash = fetchedData.commitHash;
|
|
248
|
+
xtref.content = fetchedData.content;
|
|
248
249
|
}
|
|
249
250
|
} }
|
|
250
251
|
}
|
|
251
252
|
|
|
252
253
|
// Fetch all term information, then write the results to JSON and JS files.
|
|
253
254
|
fetchAllTermsInfoFromGithub(skipExisting).then(() => {
|
|
254
|
-
const
|
|
255
|
-
fs.writeFileSync(outputPathJSON,
|
|
256
|
-
const stringReadyForFileWrite = `const
|
|
255
|
+
const allXTrefsStr = JSON.stringify(allXTrefs, null, 2);
|
|
256
|
+
fs.writeFileSync(outputPathJSON, allXTrefsStr, 'utf8');
|
|
257
|
+
const stringReadyForFileWrite = `const allXTrefs = ${allXTrefsStr};`;
|
|
257
258
|
fs.writeFileSync(outputPathJS, stringReadyForFileWrite, 'utf8');
|
|
258
259
|
fs.writeFileSync(outputPathJSTimeStamped, stringReadyForFileWrite, 'utf8');
|
|
259
260
|
|
|
@@ -264,7 +265,6 @@ function updateXrefs(GITHUB_API_TOKEN, skipExisting) {
|
|
|
264
265
|
});
|
|
265
266
|
}
|
|
266
267
|
|
|
267
|
-
// Export the updateXrefs and removeXref functions for use in other modules.
|
|
268
268
|
module.exports = {
|
|
269
|
-
|
|
269
|
+
updateXTrefs
|
|
270
270
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function getLocalXTrefContent(externalSpec, term) {
|
|
5
|
+
const filePath = path.join('output', 'xtrefs-data.json');
|
|
6
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
7
|
+
const xtrefs = data.xtrefs;
|
|
8
|
+
|
|
9
|
+
for (const xtref of xtrefs) {
|
|
10
|
+
if (xtref.externalSpec === externalSpec && xtref.term === term) {
|
|
11
|
+
return {content: xtref.content, commitHash: xtref.commitHash};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Function to process markdown files in a directory recursively
|
|
19
|
+
function prepareTref(directory) {
|
|
20
|
+
// Helper function to process a directory
|
|
21
|
+
function processDirectory(directory) {
|
|
22
|
+
try {
|
|
23
|
+
// Read the contents of the directory synchronously
|
|
24
|
+
const items = fs.readdirSync(directory, { withFileTypes: true });
|
|
25
|
+
|
|
26
|
+
// Loop through each item in the directory
|
|
27
|
+
items.forEach(item => {
|
|
28
|
+
const itemPath = path.join(directory, item.name);
|
|
29
|
+
if (item.isDirectory()) {
|
|
30
|
+
// If the item is a directory, call processDirectory recursively
|
|
31
|
+
processDirectory(itemPath);
|
|
32
|
+
} else if (item.isFile() && path.extname(item.name) === '.md') {
|
|
33
|
+
try {
|
|
34
|
+
// Read the file synchronously
|
|
35
|
+
let data = fs.readFileSync(itemPath, 'utf8');
|
|
36
|
+
|
|
37
|
+
// Split the content into lines
|
|
38
|
+
let lines = data.split('\n');
|
|
39
|
+
let localXTrefContent = '';
|
|
40
|
+
// Handle specific functionality for `[[tref:` lines
|
|
41
|
+
for (let i = 0; i < lines.length; i++) {
|
|
42
|
+
if (lines[i].startsWith('[[tref:')) {
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
\[\[tref: matches the literal [[tref:.
|
|
46
|
+
|
|
47
|
+
(.*?) captures everything lazily until the next part of the regex.
|
|
48
|
+
|
|
49
|
+
\]\] matches the literal ]].
|
|
50
|
+
|
|
51
|
+
match[1] contains the captured group, which is then split by , to form an array.
|
|
52
|
+
|
|
53
|
+
The map function trims spaces from each entry in the resulting array.
|
|
54
|
+
*/
|
|
55
|
+
const tref = /\[\[tref:(.*?)\]\]/;
|
|
56
|
+
const match = lines[i].match(tref);
|
|
57
|
+
if (match) {
|
|
58
|
+
const result = match[1].split(',').map(term => term.trim());
|
|
59
|
+
localXTrefContent = getLocalXTrefContent(result[0], result[1]);
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
|
|
63
|
+
Remove the `[[def: ...]]:` lines from the content.
|
|
64
|
+
|
|
65
|
+
\[\[def: matches the literal [[def:
|
|
66
|
+
|
|
67
|
+
.*? lazily matches any character(including commas) until the next part of the regex.
|
|
68
|
+
|
|
69
|
+
\]\]: matches the literal ]]:.
|
|
70
|
+
|
|
71
|
+
The g flag ensures that all occurrences in the string are replaced.
|
|
72
|
+
*/
|
|
73
|
+
const defPart = /\[\[def: .*?\]\]:/g;
|
|
74
|
+
localXTrefContent.content = localXTrefContent.content.replace(defPart, '');
|
|
75
|
+
|
|
76
|
+
fs.writeFileSync(itemPath, match[0] + '\n\n' + '<!-- This is a copy of the saved remote text. Remove it if you like. It is automatically (re)generated --><span class="transcluded-xref-term">transcluded xref</span>' + '\n\n~ Commit Hash: ' + localXTrefContent.commitHash + localXTrefContent.content, 'utf8');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (err) {
|
|
81
|
+
console.error(`\n SPEC-UP-T: Error reading or writing file ${item.name}: ${err}` + "\n");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error(`\n SPEC-UP-T: Error reading directory: ${err}` + "\n");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Start processing from the given directory
|
|
91
|
+
processDirectory(directory);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
prepareTref
|
|
96
|
+
};
|