spec-up-t 1.2.2 → 1.2.4

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 (49) hide show
  1. package/.sonarlint/connectedMode.json +5 -0
  2. package/assets/compiled/body.js +31 -31
  3. package/assets/compiled/head.css +5 -5
  4. package/assets/compiled/head.js +3 -3
  5. package/assets/css/adjust-font-size.css +6 -11
  6. package/assets/css/backToTop.css +0 -1
  7. package/assets/css/index.css +1 -2
  8. package/assets/css/pdf-styles.css +23 -27
  9. package/assets/css/repo-issues.css +0 -6
  10. package/assets/css/search.css +0 -1
  11. package/assets/css/sidebar-toc.css +13 -12
  12. package/assets/css/terms-and-definitions.css +43 -37
  13. package/assets/js/add-href-to-snapshot-link.js +2 -1
  14. package/assets/js/addAnchorsToTerms.js +0 -1
  15. package/assets/js/adjust-font-size.js +0 -9
  16. package/assets/js/create-alphabet-index.js +1 -1
  17. package/assets/js/custom-elements.js +13 -18
  18. package/assets/js/declare-markdown-it.js +1 -1
  19. package/assets/js/highlightMenuItems.js +3 -3
  20. package/assets/js/index.js +1 -5
  21. package/assets/js/insert-trefs.js +2 -2
  22. package/assets/js/modal.js +3 -3
  23. package/assets/js/search.js +3 -3
  24. package/assets/js/utils.js +2 -3
  25. package/index.js +5 -15
  26. package/package.json +2 -2
  27. package/src/add-remove-xref-source.js +0 -2
  28. package/src/collect-external-references.js +187 -179
  29. package/src/collectExternalReferences/fetchTermsFromIndex.js +2 -1
  30. package/src/create-external-specs-list.js +1 -1
  31. package/src/fix-markdown-files.js +152 -90
  32. package/src/health-check/external-specs-checker.js +173 -94
  33. package/src/health-check/output-gitignore-checker.js +327 -191
  34. package/src/health-check/specs-configuration-checker.js +288 -210
  35. package/src/health-check/term-references-checker.js +200 -123
  36. package/src/health-check/tref-term-checker.js +264 -179
  37. package/src/health-check.js +51 -35
  38. package/src/init.js +0 -3
  39. package/src/install-from-boilerplate/boilerplate/gitignore +2 -1
  40. package/src/install-from-boilerplate/config-system-files.js +9 -1
  41. package/src/install-from-boilerplate/copy-system-files.js +1 -1
  42. package/src/install-from-boilerplate/menu.sh +17 -3
  43. package/src/markdown-it-extensions.js +199 -106
  44. package/src/references.js +1 -2
  45. package/src/utils/doesUrlExist.js +7 -5
  46. package/templates/template.html +1 -2
  47. package/assets/js/insert-xrefs.js +0 -370
  48. package/src/create-term-relations.js +0 -131
  49. package/src/prepare-tref.js +0 -174
@@ -2,99 +2,161 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { shouldProcessFile } = require('./utils/file-filter');
4
4
 
5
- // Function to process markdown files in a directory recursively
6
- function fixMarkdownFiles(directory) {
7
- // Helper function to process a directory
8
- function processDirectory(directory) {
9
- try {
10
- // Read the contents of the directory synchronously
11
- const items = fs.readdirSync(directory, { withFileTypes: true });
12
-
13
- // Loop through each item in the directory
14
- items.forEach(item => {
15
- const itemPath = path.join(directory, item.name);
16
- if (item.isDirectory()) {
17
- // If the item is a directory, call processDirectory recursively
18
- processDirectory(itemPath);
19
- } else if (item.isFile() && shouldProcessFile(item.name)) {
20
- try {
21
- // Read the file synchronously
22
- let data = fs.readFileSync(itemPath, 'utf8');
23
-
24
- // Split the content into lines
25
- let lines = data.split('\n');
26
- let modified = false;
27
-
28
- // Handle specific functionality for `[[def:` lines
29
- for (let i = 0; i < lines.length; i++) {
30
- if (lines[i].startsWith('[[def:')) {
31
- // Ensure a blank line immediately follows `[[def:` lines
32
- if (i + 1 < lines.length && lines[i + 1].trim() !== '') {
33
- lines.splice(i + 1, 0, ''); // Insert blank line
34
- modified = true;
35
- }
36
- }
37
- }
38
-
39
- // Ensure there is exactly one blank line between paragraphs
40
- let newLines = [];
41
- let previousLineWasEmpty = false;
42
-
43
- for (let i = 0; i < lines.length; i++) {
44
- const isCurrentLineEmpty = lines[i].trim() === '';
45
-
46
- if (!isCurrentLineEmpty) {
47
- newLines.push(lines[i]); // Add non-empty lines
48
- previousLineWasEmpty = false;
49
- } else if (!previousLineWasEmpty) {
50
- newLines.push(''); // Add exactly one blank line
51
- previousLineWasEmpty = true;
52
- } else {
53
- modified = true; // Skip additional blank lines
54
- }
55
- }
56
-
57
- // Prepend `~ ` to lines that do not start with `[[def:`, `[[tref:`, are not blank, do not already start with `~ `, and are not HTML comments
58
- for (let i = 0; i < newLines.length; i++) {
59
- if (
60
- !newLines[i].startsWith('[[def:') &&
61
- !newLines[i].startsWith('[[tref:') &&
62
- newLines[i].trim() !== '' &&
63
- !newLines[i].startsWith('~ ') &&
64
- !newLines[i].trim().startsWith('<!--')
65
- ) {
66
- newLines[i] = `~ ${newLines[i]}`;
67
- modified = true;
68
- }
69
- }
70
-
71
- // Ensure there is exactly one blank line at the end of the file
72
- if (newLines[newLines.length - 1] !== '') {
73
- newLines.push('');
74
- modified = true;
75
- }
76
-
77
- // Join the lines back into a single string
78
- if (modified) {
79
- data = newLines.join('\n');
80
- }
81
-
82
- // Write the modified content back to the file synchronously if there were any changes
83
- if (modified) {
84
- fs.writeFileSync(itemPath, data, 'utf8');
85
- }
86
- } catch (err) {
87
- console.error(`❌ Error while trying to fix the markdown in file ${item.name}: ${err}`);
88
- }
89
- }
90
- });
91
- } catch (err) {
92
- console.error(`❌ Error reading directory: ${err}`);
5
+ /**
6
+ * Handles specific functionality for `[[def:` lines
7
+ * @param {string[]} lines - Array of file lines
8
+ * @returns {object} - Object containing modified lines and modification status
9
+ */
10
+ function processDefLines(lines) {
11
+ const result = [...lines];
12
+ let modified = false;
13
+
14
+ for (let i = 0; i < result.length; i++) {
15
+ if (result[i].startsWith('[[def:')) {
16
+ // Ensure a blank line immediately follows `[[def:` lines
17
+ if (i + 1 < result.length && result[i + 1].trim() !== '') {
18
+ result.splice(i + 1, 0, ''); // Insert blank line
19
+ modified = true;
20
+ }
21
+ }
22
+ }
23
+
24
+ return { lines: result, modified };
25
+ }
26
+
27
+ /**
28
+ * Ensures there is exactly one blank line between paragraphs
29
+ * @param {string[]} lines - Array of file lines
30
+ * @returns {object} - Object containing modified lines and modification status
31
+ */
32
+ function normalizeParagraphSpacing(lines) {
33
+ let newLines = [];
34
+ let previousLineWasEmpty = false;
35
+ let modified = false;
36
+
37
+ for (const line of lines) {
38
+ const isCurrentLineEmpty = line.trim() === '';
39
+
40
+ if (!isCurrentLineEmpty) {
41
+ newLines.push(line); // Add non-empty lines
42
+ previousLineWasEmpty = false;
43
+ } else if (!previousLineWasEmpty) {
44
+ newLines.push(''); // Add exactly one blank line
45
+ previousLineWasEmpty = true;
46
+ } else {
47
+ modified = true; // Skip additional blank lines
93
48
  }
94
49
  }
95
50
 
96
- // Start processing from the given directory
97
- processDirectory(directory);
51
+ return { lines: newLines, modified };
52
+ }
53
+
54
+ /**
55
+ * Prepends `~ ` to appropriate lines
56
+ * @param {string[]} lines - Array of file lines
57
+ * @returns {object} - Object containing modified lines and modification status
58
+ */
59
+ function prependTildeToLines(lines) {
60
+ const result = [...lines];
61
+ let modified = false;
62
+
63
+ for (let i = 0; i < result.length; i++) {
64
+ if (
65
+ !result[i].startsWith('[[def:') &&
66
+ !result[i].startsWith('[[tref:') &&
67
+ result[i].trim() !== '' &&
68
+ !result[i].startsWith('~ ') &&
69
+ !result[i].trim().startsWith('<!--')
70
+ ) {
71
+ result[i] = `~ ${result[i]}`;
72
+ modified = true;
73
+ }
74
+ }
75
+
76
+ return { lines: result, modified };
77
+ }
78
+
79
+ /**
80
+ * Ensures there is exactly one blank line at the end of the file
81
+ * @param {string[]} lines - Array of file lines
82
+ * @returns {object} - Object containing modified lines and modification status
83
+ */
84
+ function ensureTrailingNewline(lines) {
85
+ const result = [...lines];
86
+ let modified = false;
87
+
88
+ if (result[result.length - 1] !== '') {
89
+ result.push('');
90
+ modified = true;
91
+ }
92
+
93
+ return { lines: result, modified };
94
+ }
95
+
96
+ /**
97
+ * Processes a single markdown file and applies formatting rules
98
+ * @param {string} filePath - Path to the markdown file
99
+ * @returns {void}
100
+ */
101
+ function processMarkdownFile(filePath, fileName) {
102
+ try {
103
+ // Read the file synchronously
104
+ let data = fs.readFileSync(filePath, 'utf8');
105
+
106
+ // Split the content into lines
107
+ let lines = data.split('\n');
108
+ let modified = false;
109
+
110
+ // Apply each processing function in sequence
111
+ const defResult = processDefLines(lines);
112
+ lines = defResult.lines;
113
+ modified = modified || defResult.modified;
114
+
115
+ const spacingResult = normalizeParagraphSpacing(lines);
116
+ lines = spacingResult.lines;
117
+ modified = modified || spacingResult.modified;
118
+
119
+ const tildeResult = prependTildeToLines(lines);
120
+ lines = tildeResult.lines;
121
+ modified = modified || tildeResult.modified;
122
+
123
+ const newlineResult = ensureTrailingNewline(lines);
124
+ lines = newlineResult.lines;
125
+ modified = modified || newlineResult.modified;
126
+
127
+ // Write the modified content back to the file synchronously if there were any changes
128
+ if (modified) {
129
+ const newData = lines.join('\n');
130
+ fs.writeFileSync(filePath, newData, 'utf8');
131
+ }
132
+ } catch (err) {
133
+ console.error(`❌ Error while trying to fix the markdown in file ${fileName}: ${err}`);
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Processes markdown files in a directory recursively
139
+ * @param {string} directory - The directory to process
140
+ * @returns {void}
141
+ */
142
+ function fixMarkdownFiles(directory) {
143
+ try {
144
+ // Read the contents of the directory synchronously
145
+ const items = fs.readdirSync(directory, { withFileTypes: true });
146
+
147
+ // Loop through each item in the directory
148
+ items.forEach(item => {
149
+ const itemPath = path.join(directory, item.name);
150
+ if (item.isDirectory()) {
151
+ // If the item is a directory, call fixMarkdownFiles recursively
152
+ fixMarkdownFiles(itemPath);
153
+ } else if (item.isFile() && shouldProcessFile(item.name)) {
154
+ processMarkdownFile(itemPath, item.name);
155
+ }
156
+ });
157
+ } catch (err) {
158
+ console.error(`❌ Error reading directory: ${err}`);
159
+ }
98
160
  }
99
161
 
100
162
  module.exports = {
@@ -17,6 +17,7 @@ function isValidGitHubPagesUrl(urlStr) {
17
17
  parsedUrl.hostname.endsWith('.github.io')
18
18
  );
19
19
  } catch (error) {
20
+ console.error(`❌ Error validating GitHub Pages URL: ${error.message}`);
20
21
  return false;
21
22
  }
22
23
  }
@@ -34,6 +35,7 @@ function isValidGitHubRepoUrl(urlStr) {
34
35
  parsedUrl.pathname.split('/').filter(Boolean).length >= 2
35
36
  );
36
37
  } catch (error) {
38
+ console.error(`❌ Error validating GitHub repo URL: ${error.message}`);
37
39
  return false;
38
40
  }
39
41
  }
@@ -69,131 +71,208 @@ function urlExists(urlStr) {
69
71
 
70
72
  req.end();
71
73
  } catch (error) {
74
+ console.error(`❌ URL Format Error: Invalid URL format for ${urlStr} - ${error.message}`);
72
75
  resolve(false);
73
76
  }
74
77
  });
75
78
  }
76
79
 
77
80
  /**
78
- * Check external specs in a specs.json file
81
+ * Check if specs.json file exists and read it
79
82
  * @param {string} projectRoot - Root directory of the project
80
- * @returns {Promise<Array>} - Array of check results
83
+ * @returns {Object} - Object containing results and specs data if found
81
84
  */
82
- async function checkExternalSpecs(projectRoot) {
83
- const results = [];
85
+ function checkAndReadSpecsFile(projectRoot) {
86
+ const specsPath = path.join(projectRoot, 'specs.json');
84
87
 
85
- try {
86
- const specsPath = path.join(projectRoot, 'specs.json');
87
-
88
- // Check if specs.json exists
89
- if (!fs.existsSync(specsPath)) {
90
- return [{
88
+ if (!fs.existsSync(specsPath)) {
89
+ return {
90
+ results: [{
91
91
  name: 'Find specs.json file',
92
92
  success: false,
93
93
  details: 'specs.json file not found in project root'
94
- }];
95
- }
96
-
97
- results.push({
98
- name: 'Find specs.json file',
99
- success: true,
100
- details: 'specs.json file found'
101
- });
102
-
103
- // Read specs.json
94
+ }],
95
+ specs: null
96
+ };
97
+ }
98
+
99
+ try {
104
100
  const specsContent = fs.readFileSync(specsPath, 'utf8');
105
101
  const specs = JSON.parse(specsContent);
106
102
 
107
- // Check if external_specs key exists
108
- if (!specs.specs || !Array.isArray(specs.specs) || !specs.specs.some(spec => spec.external_specs)) {
109
- results.push({
103
+ return {
104
+ results: [{
105
+ name: 'Find specs.json file',
106
+ success: true,
107
+ details: 'specs.json file found'
108
+ }],
109
+ specs
110
+ };
111
+ } catch (error) {
112
+ return {
113
+ results: [{
114
+ name: 'Parse specs.json file',
115
+ success: false,
116
+ details: `❌ Error parsing specs.json: ${error.message}`
117
+ }],
118
+ specs: null
119
+ };
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Extract external specs from specs data
125
+ * @param {Object} specs - Specs data
126
+ * @returns {Object} - Object containing results and external specs if found
127
+ */
128
+ function extractExternalSpecs(specs) {
129
+ if (!specs.specs || !Array.isArray(specs.specs) || !specs.specs.some(spec => spec.external_specs)) {
130
+ return {
131
+ results: [{
110
132
  name: 'Find external_specs in specs.json',
111
133
  success: false,
112
134
  details: 'external_specs key not found in specs.json'
113
- });
114
- return results;
135
+ }],
136
+ externalSpecs: []
137
+ };
138
+ }
139
+
140
+ const externalSpecs = [];
141
+
142
+ specs.specs.forEach(spec => {
143
+ if (spec.external_specs && Array.isArray(spec.external_specs)) {
144
+ externalSpecs.push(...spec.external_specs);
115
145
  }
116
-
117
- results.push({
146
+ });
147
+
148
+ return {
149
+ results: [{
118
150
  name: 'Find external_specs in specs.json',
119
151
  success: true,
120
152
  details: 'external_specs key found in specs.json'
153
+ }],
154
+ externalSpecs
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Check GitHub Pages URL for an external spec
160
+ * @param {Object} spec - External spec object
161
+ * @returns {Promise<Array>} - Array of check results
162
+ */
163
+ async function checkGitHubPagesUrl(spec) {
164
+ const results = [];
165
+
166
+ if (!spec.gh_page) {
167
+ results.push({
168
+ name: `Check "${spec.external_spec}" gh_page URL`,
169
+ success: false,
170
+ details: 'gh_page URL is missing'
121
171
  });
122
-
123
- // Find all external specs
124
- const externalSpecs = [];
125
- specs.specs.forEach(spec => {
126
- if (spec.external_specs && Array.isArray(spec.external_specs)) {
127
- externalSpecs.push(...spec.external_specs);
128
- }
172
+ return results;
173
+ }
174
+
175
+ const isValidGhPage = isValidGitHubPagesUrl(spec.gh_page);
176
+ results.push({
177
+ name: `Check "${spec.external_spec}" gh_page URL structure`,
178
+ success: isValidGhPage,
179
+ details: isValidGhPage
180
+ ? 'Valid GitHub Pages URL structure'
181
+ : `Invalid GitHub Pages URL structure: ${spec.gh_page}`
182
+ });
183
+
184
+ if (isValidGhPage) {
185
+ const ghPageExists = await urlExists(spec.gh_page);
186
+ results.push({
187
+ name: `Check "${spec.external_spec}" gh_page URL exists`,
188
+ success: ghPageExists,
189
+ details: ghPageExists
190
+ ? 'GitHub Pages URL is accessible'
191
+ : `GitHub Pages URL is not accessible: ${spec.gh_page}`
192
+ });
193
+ }
194
+
195
+ return results;
196
+ }
197
+
198
+ /**
199
+ * Check repository URL for an external spec
200
+ * @param {Object} spec - External spec object
201
+ * @returns {Promise<Array>} - Array of check results
202
+ */
203
+ async function checkRepositoryUrl(spec) {
204
+ const results = [];
205
+
206
+ if (!spec.url) {
207
+ results.push({
208
+ name: `Check "${spec.external_spec}" repo URL`,
209
+ success: false,
210
+ details: 'Repository URL is missing'
129
211
  });
212
+ return results;
213
+ }
214
+
215
+ const isValidRepoUrl = isValidGitHubRepoUrl(spec.url);
216
+ results.push({
217
+ name: `Check "${spec.external_spec}" repo URL structure`,
218
+ success: isValidRepoUrl,
219
+ details: isValidRepoUrl
220
+ ? 'Valid GitHub repository URL structure'
221
+ : `Invalid GitHub repository URL structure: ${spec.url}`
222
+ });
223
+
224
+ if (isValidRepoUrl) {
225
+ const repoUrlExists = await urlExists(spec.url);
226
+ results.push({
227
+ name: `Check "${spec.external_spec}" repo URL exists`,
228
+ success: repoUrlExists,
229
+ details: repoUrlExists
230
+ ? 'GitHub repository URL is accessible'
231
+ : `GitHub repository URL is not accessible: ${spec.url}`
232
+ });
233
+ }
234
+
235
+ return results;
236
+ }
237
+
238
+ /**
239
+ * Check external specs in a specs.json file
240
+ * @param {string} projectRoot - Root directory of the project
241
+ * @returns {Promise<Array>} - Array of check results
242
+ */
243
+ async function checkExternalSpecs(projectRoot) {
244
+ try {
245
+ // Check for and read specs.json file
246
+ const { results, specs } = checkAndReadSpecsFile(projectRoot);
247
+
248
+ if (!specs) {
249
+ return results;
250
+ }
251
+
252
+ // Extract external specs from specs data
253
+ const { results: extractResults, externalSpecs } = extractExternalSpecs(specs);
254
+
255
+ // Combine results
256
+ const allResults = [...results, ...extractResults];
257
+
258
+ if (externalSpecs.length === 0) {
259
+ return allResults;
260
+ }
130
261
 
131
262
  // Check each external spec
132
263
  for (const spec of externalSpecs) {
133
- // Check gh_page structure
134
- if (spec.gh_page) {
135
- const isValidGhPage = isValidGitHubPagesUrl(spec.gh_page);
136
- results.push({
137
- name: `Check "${spec.external_spec}" gh_page URL structure`,
138
- success: isValidGhPage,
139
- details: isValidGhPage
140
- ? 'Valid GitHub Pages URL structure'
141
- : `Invalid GitHub Pages URL structure: ${spec.gh_page}`
142
- });
143
-
144
- // Check if gh_page exists
145
- if (isValidGhPage) {
146
- const ghPageExists = await urlExists(spec.gh_page);
147
- results.push({
148
- name: `Check "${spec.external_spec}" gh_page URL exists`,
149
- success: ghPageExists,
150
- details: ghPageExists
151
- ? 'GitHub Pages URL is accessible'
152
- : `GitHub Pages URL is not accessible: ${spec.gh_page}`
153
- });
154
- }
155
- } else {
156
- results.push({
157
- name: `Check "${spec.external_spec}" gh_page URL`,
158
- success: false,
159
- details: 'gh_page URL is missing'
160
- });
161
- }
264
+ // Check GitHub Pages URL
265
+ const ghPageResults = await checkGitHubPagesUrl(spec);
266
+ allResults.push(...ghPageResults);
162
267
 
163
- // Check url structure
164
- if (spec.url) {
165
- const isValidRepoUrl = isValidGitHubRepoUrl(spec.url);
166
- results.push({
167
- name: `Check "${spec.external_spec}" repo URL structure`,
168
- success: isValidRepoUrl,
169
- details: isValidRepoUrl
170
- ? 'Valid GitHub repository URL structure'
171
- : `Invalid GitHub repository URL structure: ${spec.url}`
172
- });
173
-
174
- // Check if url exists
175
- if (isValidRepoUrl) {
176
- const repoUrlExists = await urlExists(spec.url);
177
- results.push({
178
- name: `Check "${spec.external_spec}" repo URL exists`,
179
- success: repoUrlExists,
180
- details: repoUrlExists
181
- ? 'GitHub repository URL is accessible'
182
- : `GitHub repository URL is not accessible: ${spec.url}`
183
- });
184
- }
185
- } else {
186
- results.push({
187
- name: `Check "${spec.external_spec}" repo URL`,
188
- success: false,
189
- details: 'Repository URL is missing'
190
- });
191
- }
268
+ // Check repository URL
269
+ const repoUrlResults = await checkRepositoryUrl(spec);
270
+ allResults.push(...repoUrlResults);
192
271
  }
193
272
 
194
- return results;
273
+ return allResults;
195
274
  } catch (error) {
196
- console.error('Error checking external specs:', error);
275
+ console.error('Error checking external specs:', error);
197
276
  return [{
198
277
  name: 'External specs check',
199
278
  success: false,