spec-up-t 1.2.3 → 1.2.5

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 (61) hide show
  1. package/.sonarlint/connectedMode.json +5 -0
  2. package/assets/compiled/body.js +35 -32
  3. package/assets/compiled/head.css +7 -5
  4. package/assets/compiled/head.js +3 -3
  5. package/assets/css/add-bootstrap-classes-to-images.css +34 -0
  6. package/assets/css/adjust-font-size.css +6 -11
  7. package/assets/css/backToTop.css +0 -1
  8. package/assets/css/image-full-size.css +44 -0
  9. package/assets/css/index.css +1 -2
  10. package/assets/css/pdf-styles.css +23 -27
  11. package/assets/css/repo-issues.css +0 -6
  12. package/assets/css/search.css +0 -1
  13. package/assets/css/sidebar-toc.css +13 -12
  14. package/assets/css/terms-and-definitions.css +43 -37
  15. package/assets/js/add-bootstrap-classes-to-images.js +98 -0
  16. package/assets/js/add-href-to-snapshot-link.js +2 -1
  17. package/assets/js/addAnchorsToTerms.js +0 -1
  18. package/assets/js/adjust-font-size.js +0 -9
  19. package/assets/js/create-alphabet-index.js +12 -3
  20. package/assets/js/create-term-filter.js +12 -0
  21. package/assets/js/custom-elements.js +13 -18
  22. package/assets/js/declare-markdown-it.js +1 -1
  23. package/assets/js/hide-show-utility-container.js +17 -0
  24. package/assets/js/highlightMenuItems.js +3 -3
  25. package/assets/js/image-full-size.js +76 -0
  26. package/assets/js/index.js +1 -5
  27. package/assets/js/insert-trefs.js +2 -2
  28. package/assets/js/modal.js +3 -3
  29. package/assets/js/search.js +15 -3
  30. package/assets/js/utils.js +2 -3
  31. package/index.js +7 -17
  32. package/package.json +2 -2
  33. package/src/README.md +3 -3
  34. package/src/add-remove-xref-source.js +0 -2
  35. package/src/asset-map.json +5 -0
  36. package/src/collect-external-references.js +187 -179
  37. package/src/collectExternalReferences/fetchTermsFromIndex.js +2 -1
  38. package/src/config/paths.js +2 -2
  39. package/src/create-external-specs-list.js +1 -1
  40. package/src/create-term-index.js +126 -22
  41. package/src/fix-markdown-files.js +152 -90
  42. package/src/health-check/external-specs-checker.js +173 -94
  43. package/src/health-check/output-gitignore-checker.js +327 -191
  44. package/src/health-check/specs-configuration-checker.js +288 -210
  45. package/src/health-check/term-references-checker.js +200 -123
  46. package/src/health-check/tref-term-checker.js +264 -179
  47. package/src/health-check.js +52 -36
  48. package/src/init.js +1 -4
  49. package/src/insert-term-index.js +5 -5
  50. package/src/install-from-boilerplate/add-scripts-keys.js +3 -1
  51. package/src/install-from-boilerplate/boilerplate/gitignore +2 -1
  52. package/src/install-from-boilerplate/config-system-files.js +9 -1
  53. package/src/install-from-boilerplate/copy-system-files.js +1 -1
  54. package/src/markdown-it-extensions.js +199 -106
  55. package/src/references.js +1 -2
  56. package/src/utils/doesUrlExist.js +7 -5
  57. package/src/utils/fetch.js +14 -14
  58. package/templates/template.html +1 -2
  59. package/assets/js/insert-xrefs.js +0 -370
  60. package/src/create-term-relations.js +0 -131
  61. package/src/prepare-tref.js +0 -174
@@ -1,41 +1,145 @@
1
1
  /**
2
2
  * Steps:
3
- * 1. Reads the configuration from 'specs.json'.
4
- * 2. Extracts the directories containing the specifications and terms.
5
- * 3. Lists all file names in the specified terms directory.
3
+ * 1. Reads the configuration from 'specs.json', with fallbacks for missing or invalid files.
4
+ * 2. Extracts the directories containing the specifications and terms, with defaults for missing values.
5
+ * 3. Lists all file names in the specified terms directory if it exists.
6
6
  * 4. Joins each file name with the terms directory path.
7
- * 5. Creates an 'output' directory in the project root if it does not exist.
7
+ * 5. Creates an '.cache' directory in the project root if it does not exist.
8
8
  * 6. Writes the list of file paths to 'term-index.json' in the project root.
9
9
  *
10
+ * If any errors occur during the process, appropriate warnings are logged, and an empty term index
11
+ * will be created rather than throwing fatal errors.
12
+ *
10
13
  * @requires fs-extra - File system operations with extra methods.
11
14
  * @requires path - Utilities for working with file and directory paths.
12
15
  * @file src/create-term-index.js
13
16
  * @author Kor Dwarshuis
14
- * @version 1.0.0
17
+ * @version 1.1.0
15
18
  * @since 2024-09-02
16
19
  */
17
20
 
18
21
  const { shouldProcessFile } = require('./utils/file-filter');
19
22
 
20
23
  function createTermIndex() {
21
- const fs = require('fs-extra');
22
- const path = require('path');
23
- const config = fs.readJsonSync('specs.json');
24
- const specDirectories = config.specs.map(spec => spec.spec_directory);
25
- const specTermDirectoryName = config.specs.map(spec => spec.spec_terms_directory);
26
- const outputPathJSON = path.join('output', 'term-index.json');
27
- const files = fs.readdirSync(path.join(specDirectories[0], specTermDirectoryName[0]))
28
- .filter(shouldProcessFile);
29
-
30
- const filePaths = files.map(file => specTermDirectoryName[0] + '/' + file);
31
-
32
- if (!fs.existsSync('output')) {
33
- fs.mkdirSync('output');
24
+ try {
25
+ const fs = require('fs-extra');
26
+ const path = require('path');
27
+ const configPath = 'specs.json';
28
+
29
+ // Check if specs.json exists
30
+ if (!fs.existsSync(configPath)) {
31
+ console.warn(`Config file '${configPath}' not found. Using default configuration.`);
32
+ var config = { specs: [] };
33
+ } else {
34
+ // Read config with try-catch to handle parsing errors
35
+ try {
36
+ var config = fs.readJsonSync(configPath);
37
+ } catch (readError) {
38
+ console.warn(`Error reading config file: ${readError.message}. Using default configuration.`);
39
+ var config = { specs: [] };
40
+ }
41
+ }
42
+
43
+ // Provide defaults for missing config
44
+ if (!config) {
45
+ console.warn('Config file is empty or invalid. Using defaults.');
46
+ config = { specs: [] };
47
+ }
48
+
49
+ if (!config.specs) {
50
+ console.warn('No specs array found in config. Creating empty specs array.');
51
+ config.specs = [];
52
+ } else if (!Array.isArray(config.specs)) {
53
+ console.warn('Config specs is not an array. Converting to array.');
54
+ config.specs = [config.specs]; // Convert to array if it's an object
55
+ }
56
+
57
+ // If no valid specs, create an empty term index
58
+ if (config.specs.length === 0) {
59
+ console.warn('No specs found in configuration. Creating an empty term index.');
60
+ }
61
+
62
+ // Extract spec directories with fallback to current directory
63
+ const specDirectories = config.specs.map((spec, index) => {
64
+ if (!spec.spec_directory) {
65
+ console.warn(`Warning: spec_directory missing in specs.json entry #${index + 1}. Using current directory.`);
66
+ return '.'; // Default to current directory
67
+ }
68
+ return spec.spec_directory;
69
+ });
70
+
71
+ // Extract term directories with fallback to default value
72
+ const specTermDirectoryName = config.specs.map((spec, index) => {
73
+ if (!spec.spec_terms_directory) {
74
+ console.warn(`Warning: spec_terms_directory missing in specs.json entry #${index + 1}. Using default 'terms' directory.`);
75
+ return 'terms'; // Default directory name for terms
76
+ }
77
+ return spec.spec_terms_directory;
78
+ });
79
+
80
+ // Safety check - if we have no valid entries, warn and exit cleanly
81
+ if (specDirectories.length === 0 || specTermDirectoryName.length === 0) {
82
+ console.log('No term directories found in configuration. Creating empty term index.');
83
+
84
+ // Create an empty term index
85
+ const outputPathJSON = path.join('.cache', 'term-index.json');
86
+ if (!fs.existsSync('.cache')) {
87
+ fs.mkdirSync('.cache', { recursive: true });
88
+ }
89
+ fs.writeJsonSync(outputPathJSON, [], { spaces: 2 });
90
+ console.log(`✅ Empty term index created at: ${outputPathJSON}`);
91
+ return; // Exit function early
92
+ }
93
+
94
+ // Verify that the base spec directory exists
95
+ const baseSpecDir = specDirectories[0];
96
+ if (!baseSpecDir || !fs.existsSync(baseSpecDir)) {
97
+ console.warn(`Spec directory '${baseSpecDir}' does not exist. Creating empty term index.`);
98
+
99
+ // Create an empty term index
100
+ const outputPathJSON = path.join('.cache', 'term-index.json');
101
+ if (!fs.existsSync('.cache')) {
102
+ fs.mkdirSync('.cache', { recursive: true });
103
+ }
104
+ fs.writeJsonSync(outputPathJSON, [], { spaces: 2 });
105
+ console.log(`✅ Empty term index created at: ${outputPathJSON}`);
106
+ return; // Exit function early
107
+ }
108
+
109
+ // Verify that the terms directory exists
110
+ const termsDir = path.join(baseSpecDir, specTermDirectoryName[0]);
111
+
112
+ let files = [];
113
+ if (!fs.existsSync(termsDir)) {
114
+ console.warn(`Terms directory '${termsDir}' does not exist. Creating an empty term index.`);
115
+ } else {
116
+ // Get list of files and filter them
117
+ files = fs.readdirSync(termsDir).filter(shouldProcessFile);
118
+ }
119
+
120
+ if (files.length === 0) {
121
+ console.log('Warning: No term files found to process.');
122
+ }
123
+
124
+ const filePaths = files.map(file => specTermDirectoryName[0] + '/' + file);
125
+ const outputPathJSON = path.join('.cache', 'term-index.json');
126
+
127
+ // Create .cache directory if it doesn't exist
128
+ if (!fs.existsSync('.cache')) {
129
+ fs.mkdirSync('.cache', { recursive: true });
130
+ }
131
+
132
+ // Write the term index file
133
+ try {
134
+ fs.writeJsonSync(outputPathJSON, filePaths, { spaces: 2 });
135
+ console.log(`✅ Term index created with ${files.length} terms. Output: ${outputPathJSON}`);
136
+ } catch (writeError) {
137
+ throw new Error(`Failed to write term index file: ${writeError.message}`);
138
+ }
139
+ } catch (error) {
140
+ console.error(`❌ Error creating term index: ${error.message}`);
141
+ throw error;
34
142
  }
35
-
36
- fs.writeJsonSync(outputPathJSON, filePaths, { spaces: 2 });
37
-
38
- console.log(`✅ The new terms were added. All done.`);
39
143
  }
40
144
 
41
145
  module.exports = {
@@ -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 = {