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 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.30",
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
+ }
@@ -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
- const specDirectories = config.specs.map(spec => spec.spec_directory + '/' + spec.spec_terms_directory);
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 outputPath = 'output/xrefs-data.js';
26
- const outputPathTimeStamped = 'output/xrefs-history/xrefs-data-' + Date.now() + '.js';
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(`Github API request for the term “${match.term} was successful`);
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
- // Process the last ten commits
76
- const commits = data.slice(0, 1); // Get only the last commit
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(`Commit hash found for the term “${match.term}”: `, commitHash);
80
- return commitHash;
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
- // return;
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('All “spec_directory” found in specs.json: ', specDirectories);
90
- specDirectories.forEach(specDirectory => {
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: [[xref: PE, Holder]]
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
- // remove[[xref:” from the beginning of every value in allMatches
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
- // remove “]]” from the end of every value in allMatches
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": "PE",
160
- // "url": "https://github.com/decentralized-identity/presentation-exchange",
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
- // "PE": "https://identity.foundation/presentation-exchange"
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(outputPath, stringReadyForFileWrite, 'utf8');
236
- fs.writeFileSync(outputPathTimeStamped, stringReadyForFileWrite, 'utf8');
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
+ };