spec-up-t 0.11.30 → 0.11.32
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/index.js +3 -0
- package/package.json +3 -7
- package/src/get-xrefs-data.js +107 -36
- package/src/json-key-validator.js +94 -0
package/index.js
CHANGED
|
@@ -7,6 +7,9 @@ module.exports = function(options = {}) {
|
|
|
7
7
|
findExternalSpecByKey
|
|
8
8
|
} = require('./references.js');
|
|
9
9
|
|
|
10
|
+
const { runJsonKeyValidatorSync } = require('./src/json-key-validator.js');
|
|
11
|
+
runJsonKeyValidatorSync();
|
|
12
|
+
|
|
10
13
|
const { processMarkdownFiles } = require('./src/fix-markdown-files.js');
|
|
11
14
|
processMarkdownFiles('./spec');
|
|
12
15
|
|
package/package.json
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-up-t",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.32",
|
|
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": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/blockchainbird/spec-up-t.git"
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"edit": "node -e \"require('./index')()\"",
|
|
12
|
-
"render": "node -e \"require('./index')({ nowatch: true })\"",
|
|
13
|
-
"dev": "node -e \"require('./index')({ dev: true })\""
|
|
14
|
-
},
|
|
15
10
|
"keywords": [
|
|
16
11
|
"spec",
|
|
17
12
|
"specs",
|
|
@@ -56,6 +51,7 @@
|
|
|
56
51
|
"merge-stream": "2.0.0",
|
|
57
52
|
"pkg-dir": "4.2.0",
|
|
58
53
|
"prismjs": ">=1.24.0",
|
|
54
|
+
"readline-sync": "^1.4.10",
|
|
59
55
|
"yargs": "16.2.0"
|
|
60
56
|
}
|
|
61
|
-
}
|
|
57
|
+
}
|
package/src/get-xrefs-data.js
CHANGED
|
@@ -5,25 +5,26 @@
|
|
|
5
5
|
* @since 2024-06-09
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
// Get the current working directory
|
|
9
|
-
|
|
10
8
|
const fs = require('fs-extra');
|
|
11
9
|
const config = fs.readJsonSync('specs.json');
|
|
12
|
-
|
|
10
|
+
|
|
11
|
+
// Collect all directories that contain files with a term and definition
|
|
12
|
+
const specTermsDirectories = config.specs.map(spec => spec.spec_directory + '/' + spec.spec_terms_directory);
|
|
13
13
|
|
|
14
14
|
// Create directory named “output” in the project root if it does not yet exist
|
|
15
15
|
if (!fs.existsSync('output')) {
|
|
16
16
|
fs.mkdirSync('output');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
// Create directory named “output/xrefs” in the project root if it does not yet exist
|
|
19
|
+
// Create directory named “output/xrefs-history” in the project root if it does not yet exist
|
|
20
20
|
if (!fs.existsSync('output/xrefs-history')) {
|
|
21
21
|
fs.mkdirSync('output/xrefs-history');
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// Create a path for the output file in the project root
|
|
25
|
-
const
|
|
26
|
-
const
|
|
25
|
+
const outputPathJSON = 'output/xrefs-data.json';
|
|
26
|
+
const outputPathJS = 'output/xrefs-data.js';
|
|
27
|
+
const outputPathJSTimeStamped = 'output/xrefs-history/xrefs-data-' + Date.now() + '.js';
|
|
27
28
|
|
|
28
29
|
function getXrefsData() {
|
|
29
30
|
let allXrefs = {};
|
|
@@ -31,6 +32,22 @@ function getXrefsData() {
|
|
|
31
32
|
|
|
32
33
|
// Function to fetch the latest commit hash of the file
|
|
33
34
|
async function fetchLatestCommitHash(match) {
|
|
35
|
+
/* Example
|
|
36
|
+
console.log('match: ', match); ->
|
|
37
|
+
|
|
38
|
+
match: {
|
|
39
|
+
externalSpec: 'test-1',
|
|
40
|
+
term: 'Aal',
|
|
41
|
+
repoUrl: 'https://github.com/blockchainbird/spec-up-xref-test-1',
|
|
42
|
+
terms_dir: 'spec/term-definitions',
|
|
43
|
+
owner: 'blockchainbird',
|
|
44
|
+
repo: 'spec-up-xref-test-1',
|
|
45
|
+
site: 'https://blockchainbird.github.io/spec-up-xref-test-1/'
|
|
46
|
+
}
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
34
51
|
try {
|
|
35
52
|
|
|
36
53
|
if (match.repoUrl === undefined) {
|
|
@@ -60,9 +77,9 @@ function getXrefsData() {
|
|
|
60
77
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
61
78
|
}
|
|
62
79
|
|
|
63
|
-
console.log(
|
|
80
|
+
console.log(`\nGithub API request for:\n Term ${match.term},\n Name: ${match.externalSpec}\n Owner ${match.owner}\n Repo ${match.repo}\nwas successful`);
|
|
64
81
|
|
|
65
|
-
// Extract JSON data from the response
|
|
82
|
+
// Extract JSON data from the response, see https://blockchainbird.github.io/spec-up-t-website/docs/various-roles/developers-guide/#example-of-api-response for example response
|
|
66
83
|
const data = await response.json();
|
|
67
84
|
|
|
68
85
|
// Check if there are any commits
|
|
@@ -72,22 +89,51 @@ function getXrefsData() {
|
|
|
72
89
|
return;
|
|
73
90
|
}
|
|
74
91
|
|
|
75
|
-
//
|
|
76
|
-
const commits = data.slice(0, 1);
|
|
92
|
+
// Get only the last commit
|
|
93
|
+
const commits = data.slice(0, 1);
|
|
94
|
+
// Assign the fetched commit hash to the variable commitHash
|
|
77
95
|
const commitHash = commits.map(commit => commit.sha);
|
|
78
96
|
|
|
79
|
-
console.log(
|
|
80
|
-
|
|
97
|
+
console.log(`\nCommit hash found for the term “${match.term}”: `, commitHash);
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
//TODO: Check if a term is in the JSON file and not in the markdown file. If so, remove the term from the JSON file.
|
|
101
|
+
|
|
102
|
+
// Check if the file exists
|
|
103
|
+
if (fs.existsSync(outputPathJSON)) {
|
|
104
|
+
// Read the JSON file
|
|
105
|
+
let currentXrefs = fs.readJsonSync(outputPathJSON);
|
|
106
|
+
// Check if the term is in the JSON file
|
|
107
|
+
currentXrefs.xrefs.forEach(xref => {
|
|
108
|
+
// Check if the term is in the JSON file
|
|
109
|
+
if (xref.term === match.term) {
|
|
110
|
+
// If the term is in the JSON file, get the commit hash from the file and assign it to the variable commitHash. This is done to prevent the commit hash from being overwritten by the fetched commit hash. We want to keep the commit hash that was fetched at the time that the author looked it up.
|
|
111
|
+
console.log(`\nThis external reference:\n Term: ${match.term}\n Name: ${match.externalSpec}\n Owner: ${match.owner}\n Repo: ${match.repo}\nis already referenced.
|
|
112
|
+
`)
|
|
113
|
+
|
|
114
|
+
// Give the commitHash from the JSON file to the commitHash variable
|
|
115
|
+
commitHash = xref.commitHash;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
console.error(`File not found: ${outputPathJSON}`);
|
|
120
|
+
}
|
|
81
121
|
|
|
82
|
-
|
|
122
|
+
return commitHash;
|
|
83
123
|
} catch (error) {
|
|
84
124
|
console.error(`Failed to fetch commit hash for the term “${match.term}”:`, error);
|
|
85
125
|
}
|
|
86
126
|
}
|
|
87
127
|
|
|
128
|
+
async function fetchLatestCommitHashes() {
|
|
129
|
+
for (const xref of allXrefs.xrefs) {
|
|
130
|
+
xref.commitHash = await fetchLatestCommitHash(xref);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
88
134
|
// Go through all directories that contain files with a term and definition
|
|
89
|
-
console.log(
|
|
90
|
-
|
|
135
|
+
console.log("All “spec_directory”'s found in specs.json: ", specTermsDirectories);
|
|
136
|
+
specTermsDirectories.forEach(specDirectory => {
|
|
91
137
|
console.log(`Current spec_directory: `, specDirectory);
|
|
92
138
|
// read directory
|
|
93
139
|
fs.readdirSync(specDirectory).forEach(file => {
|
|
@@ -101,7 +147,7 @@ function getXrefsData() {
|
|
|
101
147
|
const xrefs = markdown.match(regex);
|
|
102
148
|
xrefs.forEach(xref => {
|
|
103
149
|
console.log(`Xref found in ${file}: `, xref);
|
|
104
|
-
// example of xref: [
|
|
150
|
+
// example of xref: [xref: test-1, Aal]
|
|
105
151
|
allXrefs.xrefs.add(xref);
|
|
106
152
|
});
|
|
107
153
|
}
|
|
@@ -113,26 +159,28 @@ function getXrefsData() {
|
|
|
113
159
|
|
|
114
160
|
// Example output:
|
|
115
161
|
// allXrefs.xrefs: [
|
|
116
|
-
// '[[xref: PE, Holder]]',
|
|
117
162
|
// '[[xref: test-1, Aal]]',
|
|
118
163
|
// '[[xref: test-2, Abac]]'
|
|
119
164
|
// ]
|
|
120
165
|
|
|
121
|
-
//
|
|
166
|
+
// The following steps create an array of objects with the keys “externalSpec” and “term” for each xref by splitting the xref string on the comma and removing the “[[xref:” and “]]” parts
|
|
167
|
+
|
|
168
|
+
// Step 1: remove “[[xref:” from the beginning of every value in allMatches
|
|
122
169
|
allXrefs.xrefs = allXrefs.xrefs.map(xref => {
|
|
123
170
|
return xref.replace(/\[\[xref:/, '');
|
|
124
171
|
});
|
|
125
|
-
|
|
172
|
+
|
|
173
|
+
// Step 2: remove “]]” from the end of every value in allMatches
|
|
126
174
|
allXrefs.xrefs = allXrefs.xrefs.map(xref => {
|
|
127
175
|
return xref.replace(/\]\]/, '');
|
|
128
176
|
});
|
|
129
177
|
|
|
130
|
-
// trim every entry of allMatches
|
|
178
|
+
// Step 3: trim every entry of allMatches
|
|
131
179
|
allXrefs.xrefs = allXrefs.xrefs.map(xref => {
|
|
132
180
|
return xref.trim();
|
|
133
181
|
});
|
|
134
182
|
|
|
135
|
-
// split every entry of allMatches on the first comma, replace the entry with an object that has two keys: one that contains everything before the comma and one that contains everything after the comma
|
|
183
|
+
// Step 4: split every entry of allMatches on the first comma, replace the entry with an object that has two keys: one that contains everything before the comma and one that contains everything after the comma
|
|
136
184
|
allXrefs.xrefs = allXrefs.xrefs.map(xref => {
|
|
137
185
|
let [externalSpec, term] = xref.split(/,/, 2);
|
|
138
186
|
return {
|
|
@@ -143,12 +191,11 @@ function getXrefsData() {
|
|
|
143
191
|
|
|
144
192
|
// Example output:
|
|
145
193
|
// allXrefs.xrefs: [
|
|
146
|
-
// { externalSpec: 'PE', term: 'Holder' },
|
|
147
194
|
// { externalSpec: 'test-1', term: 'Aal' },
|
|
148
195
|
// { externalSpec: 'test-2', term: 'Abac' }
|
|
149
196
|
// ]
|
|
150
197
|
|
|
151
|
-
|
|
198
|
+
// Step 5: add the url and the dir where the terms are, to the xref object
|
|
152
199
|
allXrefs.xrefs.forEach(xref => {
|
|
153
200
|
config.specs.forEach(spec => {
|
|
154
201
|
spec.external_specs_repos.forEach(repo => {
|
|
@@ -156,8 +203,8 @@ function getXrefsData() {
|
|
|
156
203
|
// Example external_specs_repos:
|
|
157
204
|
// "external_specs_repos": [
|
|
158
205
|
// {
|
|
159
|
-
// "external_spec": "
|
|
160
|
-
// "url": "https://github.com/
|
|
206
|
+
// "external_spec": "test-1",
|
|
207
|
+
// "url": "https://github.com/blockchainbird/spec-up-xref-test-1",
|
|
161
208
|
// "terms_dir": "spec"
|
|
162
209
|
// },
|
|
163
210
|
// …
|
|
@@ -170,6 +217,7 @@ function getXrefsData() {
|
|
|
170
217
|
});
|
|
171
218
|
});
|
|
172
219
|
|
|
220
|
+
// Step 6: add the owner and repo to the xref object
|
|
173
221
|
allXrefs.xrefs.forEach(xref => {
|
|
174
222
|
if (xref.repoUrl === undefined) {
|
|
175
223
|
console.log('match.repoUrl is undefined');
|
|
@@ -181,15 +229,16 @@ function getXrefsData() {
|
|
|
181
229
|
xref.repo = urlParts[2];
|
|
182
230
|
});
|
|
183
231
|
|
|
232
|
+
// Step 7: add the site to the xref object
|
|
184
233
|
allXrefs.xrefs.forEach(xref => {
|
|
185
234
|
// loop through array of specs in config
|
|
186
235
|
config.specs.forEach(spec => {
|
|
187
236
|
if (spec.external_specs) {
|
|
188
237
|
// Example external_specs:
|
|
189
238
|
// "external_specs": [
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
//
|
|
239
|
+
// {
|
|
240
|
+
// "test-1": "https://blockchainbird.github.io/spec-up-xref-test-1/"
|
|
241
|
+
// }
|
|
193
242
|
// …
|
|
194
243
|
// ]
|
|
195
244
|
spec.external_specs.forEach(externalSpec => {
|
|
@@ -217,26 +266,48 @@ function getXrefsData() {
|
|
|
217
266
|
]
|
|
218
267
|
}
|
|
219
268
|
*/
|
|
220
|
-
async function fetchLatestCommitHashes() {
|
|
221
|
-
for (const xref of allXrefs.xrefs) {
|
|
222
|
-
xref.commitHash = await fetchLatestCommitHash(xref);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
269
|
|
|
226
270
|
// Call the function and wait for it to complete before writing to the file
|
|
227
271
|
fetchLatestCommitHashes().then(() => {
|
|
228
272
|
// Convert allXrefsStr to a JSON string with indentation
|
|
229
273
|
const allXrefsStr = JSON.stringify(allXrefs, null, 2);
|
|
230
274
|
|
|
275
|
+
// // Write the JSON code to a .json file
|
|
276
|
+
fs.writeFileSync(outputPathJSON, allXrefsStr, 'utf8');
|
|
277
|
+
|
|
231
278
|
// Create the JS code for the assignment
|
|
232
279
|
const stringReadyForFileWrite = `const allXrefs = ${allXrefsStr};`;
|
|
233
280
|
|
|
234
281
|
// Write the JS code to a .js file
|
|
235
|
-
fs.writeFileSync(
|
|
236
|
-
fs.writeFileSync(
|
|
282
|
+
fs.writeFileSync(outputPathJS, stringReadyForFileWrite, 'utf8');
|
|
283
|
+
fs.writeFileSync(outputPathJSTimeStamped, stringReadyForFileWrite, 'utf8');
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Write function that removes an entry from xrefs-data.json and xrefs-data.js based on the term and externalSpec
|
|
288
|
+
function removeXref(term, externalSpec) {
|
|
289
|
+
// Read the JSON file
|
|
290
|
+
let currentXrefs = fs.readJsonSync(outputPathJSON);
|
|
291
|
+
|
|
292
|
+
// Remove the entry from the JSON file
|
|
293
|
+
currentXrefs.xrefs = currentXrefs.xrefs.filter(xref => {
|
|
294
|
+
return !(xref.term === term && xref.externalSpec === externalSpec);
|
|
237
295
|
});
|
|
296
|
+
|
|
297
|
+
// Convert the JSON object back to a JSON string
|
|
298
|
+
const currentXrefsStr = JSON.stringify(currentXrefs, null, 2);
|
|
299
|
+
|
|
300
|
+
// Write the JSON code to a .json file
|
|
301
|
+
fs.writeFileSync(outputPathJSON, currentXrefsStr, 'utf8');
|
|
302
|
+
|
|
303
|
+
// Create the JS code for the assignment
|
|
304
|
+
const stringReadyForFileWrite = `const allXrefs = ${currentXrefsStr};`;
|
|
305
|
+
|
|
306
|
+
// Write the JS code to a .js file
|
|
307
|
+
fs.writeFileSync(outputPathJS, stringReadyForFileWrite, 'utf8');
|
|
238
308
|
}
|
|
239
309
|
|
|
240
310
|
module.exports = {
|
|
241
|
-
getXrefsData
|
|
311
|
+
getXrefsData,
|
|
312
|
+
removeXref
|
|
242
313
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const readlineSync = require('readline-sync');
|
|
3
|
+
|
|
4
|
+
let errorFound = false;
|
|
5
|
+
|
|
6
|
+
// Function to pause the script and wait for the ENTER key synchronously
|
|
7
|
+
function pauseForEnterSync() {
|
|
8
|
+
readlineSync.question('Press ENTER to continue...');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function loadData() {
|
|
12
|
+
return JSON.parse(fs.readFileSync('./specs.json', 'utf8'));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function checkKeysSync(object, expectedKeys, parentKey = '') {
|
|
16
|
+
for (let key of expectedKeys) {
|
|
17
|
+
if (Array.isArray(object)) {
|
|
18
|
+
for (let [index, item] of object.entries()) {
|
|
19
|
+
checkKeysSync(item, expectedKeys, `${parentKey}[${index}]`);
|
|
20
|
+
}
|
|
21
|
+
} else if (typeof object === 'object') {
|
|
22
|
+
if (!(key in object)) {
|
|
23
|
+
console.error(` Error: Missing key '${key}' in ${parentKey}\n We cannot guarantee that Spec-Up-T will work properly.\n Here is an example specs.json file:\n https://github.com/blockchainbird/spec-up-t-starter-pack/blob/main/spec-up-t-starterpack/specs.json`);
|
|
24
|
+
errorFound = true;
|
|
25
|
+
pauseForEnterSync(); // Pause synchronously
|
|
26
|
+
}
|
|
27
|
+
if (typeof expectedKeys[key] === 'object' && object[key]) {
|
|
28
|
+
checkKeysSync(object[key], expectedKeys[key], `${parentKey}.${key}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function runJsonKeyValidatorSync() {
|
|
35
|
+
const data = loadData();
|
|
36
|
+
const expectedKeys = {
|
|
37
|
+
specs: [
|
|
38
|
+
"title",
|
|
39
|
+
"spec_directory",
|
|
40
|
+
"spec_terms_directory",
|
|
41
|
+
"output_path",
|
|
42
|
+
"markdown_paths",
|
|
43
|
+
"logo",
|
|
44
|
+
"logo_link",
|
|
45
|
+
"source",
|
|
46
|
+
"external_specs",
|
|
47
|
+
"external_specs_repos",
|
|
48
|
+
"assets",
|
|
49
|
+
"katex",
|
|
50
|
+
"searchHighlightStyle"
|
|
51
|
+
],
|
|
52
|
+
source: [
|
|
53
|
+
"host",
|
|
54
|
+
"account",
|
|
55
|
+
"repo"
|
|
56
|
+
],
|
|
57
|
+
external_specs_repos: [
|
|
58
|
+
"external_spec",
|
|
59
|
+
"url",
|
|
60
|
+
"terms_dir"
|
|
61
|
+
],
|
|
62
|
+
assets: [
|
|
63
|
+
"path",
|
|
64
|
+
"inject",
|
|
65
|
+
"module"
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
for (let [index, spec] of data.specs.entries()) {
|
|
70
|
+
console.log(` Checking spec #${index + 1}`);
|
|
71
|
+
checkKeysSync(spec, expectedKeys.specs, `specs[${index}]`);
|
|
72
|
+
|
|
73
|
+
if (spec.source) {
|
|
74
|
+
checkKeysSync(spec.source, expectedKeys.source, `specs[${index}].source`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (spec.external_specs_repos) {
|
|
78
|
+
checkKeysSync(spec.external_specs_repos, expectedKeys.external_specs_repos, `specs[${index}].external_specs_repos`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// if (spec.assets) {
|
|
82
|
+
// checkKeysSync(spec.assets, expectedKeys.assets, `specs[${index}].assets`);
|
|
83
|
+
// }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!errorFound) {
|
|
87
|
+
console.log(' All keys are present. No errors found. Continue…');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Export the function to be used in other scripts
|
|
92
|
+
module.exports = {
|
|
93
|
+
runJsonKeyValidatorSync
|
|
94
|
+
};
|