spec-up-t 1.1.54 → 1.2.0
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 +59 -8
- package/assets/compiled/head.css +13 -12
- package/assets/css/adjust-font-size.css +11 -0
- package/assets/css/collapse-meta-info.css +27 -8
- package/assets/css/create-term-filter.css +11 -0
- package/assets/css/index.css +15 -0
- package/assets/css/prism.css +176 -153
- package/assets/css/prism.dark.css +157 -0
- package/assets/css/prism.default.css +180 -0
- package/assets/css/terms-and-definitions.1.css +223 -0
- package/assets/css/terms-and-definitions.css +214 -100
- package/assets/js/addAnchorsToTerms.js +1 -1
- package/assets/js/collapse-definitions.js +2 -1
- package/assets/js/collapse-meta-info.js +25 -11
- package/assets/js/create-term-filter.js +61 -0
- package/assets/js/horizontal-scroll-hint.js +159 -0
- package/assets/js/index.1.js +137 -0
- package/assets/js/index.js +2 -1
- package/assets/js/insert-trefs.js +122 -116
- package/assets/js/insert-xrefs.1.js +372 -0
- package/assets/js/{show-commit-hashes.js → insert-xrefs.js} +67 -7
- package/assets/js/prism.dark.js +24 -0
- package/assets/js/prism.default.js +23 -0
- package/assets/js/prism.js +4 -5
- package/assets/js/search.js +1 -1
- package/assets/js/toggle-dense-info.js +40 -0
- package/branches.md +4 -29
- package/index.js +397 -189
- package/index.new.js +662 -0
- package/package.json +1 -1
- package/src/asset-map.json +9 -5
- package/src/collect-external-references.js +16 -9
- package/src/collectExternalReferences/fetchTermsFromIndex.js +328 -0
- package/src/collectExternalReferences/processXTrefsData.js +73 -18
- package/src/create-pdf.js +385 -89
- package/src/health-check/external-specs-checker.js +207 -0
- package/src/health-check/output-gitignore-checker.js +261 -0
- package/src/health-check/specs-configuration-checker.js +274 -0
- package/src/health-check/term-references-checker.js +191 -0
- package/src/health-check/terms-intro-checker.js +81 -0
- package/src/health-check/tref-term-checker.js +463 -0
- package/src/health-check.js +445 -0
- package/src/install-from-boilerplate/config-scripts-keys.js +2 -0
- package/src/install-from-boilerplate/menu.sh +6 -3
- package/src/markdown-it-extensions.js +134 -103
- package/src/prepare-tref.js +61 -24
- package/src/utils/fetch.js +100 -0
- package/templates/template.html +12 -7
- package/assets/js/css-helper.js +0 -30
- package/src/collectExternalReferences/fetchTermsFromGitHubRepository.js +0 -232
- package/src/collectExternalReferences/fetchTermsFromGitHubRepository.test.js +0 -385
- package/src/collectExternalReferences/octokitClient.js +0 -96
|
@@ -7,6 +7,49 @@ const contentRegex = /\s*([^\s\[\]:]+):?\s*([^\]\n]+)?/i;
|
|
|
7
7
|
|
|
8
8
|
module.exports = function (md, templates = {}) {
|
|
9
9
|
|
|
10
|
+
// Add table renderer to apply Bootstrap classes to all tables by default
|
|
11
|
+
const originalTableRender = md.renderer.rules.table_open || function (tokens, idx, options, env, self) {
|
|
12
|
+
return self.renderToken(tokens, idx, options);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Save the original table_close renderer
|
|
16
|
+
const originalTableCloseRender = md.renderer.rules.table_close || function (tokens, idx, options, env, self) {
|
|
17
|
+
return self.renderToken(tokens, idx, options);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Override table_open to add both the classes and open a wrapper div
|
|
21
|
+
md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
|
|
22
|
+
// Add Bootstrap classes to the table element
|
|
23
|
+
const token = tokens[idx];
|
|
24
|
+
const classIndex = token.attrIndex('class');
|
|
25
|
+
const tableClasses = 'table table-striped table-bordered table-hover';
|
|
26
|
+
|
|
27
|
+
if (classIndex < 0) {
|
|
28
|
+
token.attrPush(['class', tableClasses]);
|
|
29
|
+
} else {
|
|
30
|
+
// If a class attribute already exists, append our classes
|
|
31
|
+
const existingClasses = token.attrs[classIndex][1];
|
|
32
|
+
// Only add classes that aren't already present
|
|
33
|
+
const classesToAdd = tableClasses
|
|
34
|
+
.split(' ')
|
|
35
|
+
.filter(cls => !existingClasses.includes(cls))
|
|
36
|
+
.join(' ');
|
|
37
|
+
|
|
38
|
+
if (classesToAdd) {
|
|
39
|
+
token.attrs[classIndex][1] = existingClasses + ' ' + classesToAdd;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Add the responsive wrapper div before the table
|
|
44
|
+
return '<div class="table-responsive">' + originalTableRender(tokens, idx, options, env, self);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Override table_close to close the wrapper div
|
|
48
|
+
md.renderer.rules.table_close = function (tokens, idx, options, env, self) {
|
|
49
|
+
// Close the table and add the closing div
|
|
50
|
+
return originalTableCloseRender(tokens, idx, options, env, self) + '</div>';
|
|
51
|
+
};
|
|
52
|
+
|
|
10
53
|
md.inline.ruler.after('emphasis', 'templates', function templates_ruler(state, silent) {
|
|
11
54
|
|
|
12
55
|
var start = state.pos;
|
|
@@ -78,7 +121,6 @@ module.exports = function (md, templates = {}) {
|
|
|
78
121
|
let classAdded = false;
|
|
79
122
|
|
|
80
123
|
md.renderer.rules.dl_open = function (tokens, idx, options, env, self) {
|
|
81
|
-
|
|
82
124
|
const targetHtml = 'terminology-section-start-h7vc6omi2hr2880';
|
|
83
125
|
let targetIndex = -1;
|
|
84
126
|
|
|
@@ -94,115 +136,35 @@ module.exports = function (md, templates = {}) {
|
|
|
94
136
|
if (targetIndex !== -1 && idx > targetIndex && !classAdded) {
|
|
95
137
|
tokens[idx].attrPush(['class', 'terms-and-definitions-list']);
|
|
96
138
|
classAdded = true;
|
|
139
|
+
}
|
|
97
140
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
1: Token-based Markdown Processing: Spec-Up-T uses a token-based approach to parse and render Markdown. When Markdown is processed, it's converted into a series of tokens that represent different elements (like dt_open, dt_content, dt_close, dd_open, dd_content, dd_close). We're not dealing with simple strings but with structured tokens.
|
|
102
|
-
|
|
103
|
-
2: Preserving Relationships: When sorting terms, we need to ensure that each definition term (<dt>) stays connected to its corresponding definition description (<dd>). It's not as simple as sorting an array of strings - we're sorting complex structures.
|
|
104
|
-
|
|
105
|
-
3: Implementation Details: The implementation includes:
|
|
106
|
-
|
|
107
|
-
- Finding the terminology section in the document
|
|
108
|
-
- Collecting term starts, ends, and their contents
|
|
109
|
-
- Creating a sorted index based on case-insensitive comparisons
|
|
110
|
-
- Rebuilding the token array in the correct order
|
|
111
|
-
- Ensuring all relationships between terms and definitions are preserved
|
|
112
|
-
- Handling special cases and edge conditions
|
|
113
|
-
|
|
114
|
-
The complexity is unavoidable because:
|
|
115
|
-
|
|
116
|
-
- We're working with the markdown-it rendering pipeline, not just manipulating DOM
|
|
117
|
-
- The terms and definitions exist as tokens before they become HTML
|
|
118
|
-
- We need to preserve all the token relationships while reordering
|
|
119
|
-
- We're intercepting the rendering process to modify the token structure
|
|
120
|
-
|
|
121
|
-
If we were just sorting DOM elements after the page rendered, it would be simpler. But by doing the sorting during the Markdown processing, we ensure the HTML output is correct from the beginning, which is more efficient and leads to better performance.
|
|
122
|
-
*/
|
|
123
|
-
let dtStartIndices = [];
|
|
124
|
-
let dtEndIndices = [];
|
|
125
|
-
let dtContents = [];
|
|
141
|
+
let lastDdIndex = -1;
|
|
142
|
+
let currentDtIndex = -1; // Track current dt to detect empty dt elements
|
|
126
143
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const startIdx = i;
|
|
134
|
-
let content = '';
|
|
135
|
-
|
|
136
|
-
// Find the end of this dt block and capture its content
|
|
137
|
-
for (let j = i + 1; j < tokens.length; j++) {
|
|
138
|
-
if (tokens[j].type === 'dt_close') {
|
|
139
|
-
dtStartIndices.push(startIdx);
|
|
140
|
-
dtEndIndices.push(j);
|
|
141
|
-
dtContents.push(content.toLowerCase()); // Store lowercase for case-insensitive sorting
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
// Collect the content inside the dt (including spans with term IDs)
|
|
145
|
-
if (tokens[j].content) {
|
|
146
|
-
content += tokens[j].content;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
144
|
+
// First pass - check for and mark empty dt elements
|
|
145
|
+
// This scan identifies definition terms that have no content (empty dt elements)
|
|
146
|
+
// which is one of the root causes of the issues we're fixing
|
|
147
|
+
for (let i = idx + 1; i < tokens.length; i++) {
|
|
148
|
+
if (tokens[i].type === 'dl_close') {
|
|
149
|
+
break;
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
// For each dt/dd pair in sorted order
|
|
162
|
-
for (let i = 0; i < sortedIndices.length; i++) {
|
|
163
|
-
const originalIndex = sortedIndices[i];
|
|
164
|
-
const dtStart = dtStartIndices[originalIndex];
|
|
165
|
-
const dtEnd = dtEndIndices[originalIndex];
|
|
166
|
-
|
|
167
|
-
// Add dt tokens
|
|
168
|
-
for (let j = dtStart; j <= dtEnd; j++) {
|
|
169
|
-
newTokens.push(tokens[j]);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Find and add dd tokens
|
|
173
|
-
let ddFound = false;
|
|
174
|
-
for (let j = dtEnd + 1; j < tokens.length; j++) {
|
|
175
|
-
if (tokens[j].type === 'dt_open' || tokens[j].type === 'dl_close') {
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
if (tokens[j].type === 'dd_open') {
|
|
179
|
-
ddFound = true;
|
|
180
|
-
}
|
|
181
|
-
if (ddFound) {
|
|
182
|
-
newTokens.push(tokens[j]);
|
|
183
|
-
if (tokens[j].type === 'dd_close') {
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Add the closing dl token
|
|
191
|
-
for (let i = idx + 1; i < tokens.length; i++) {
|
|
192
|
-
if (tokens[i].type === 'dl_close') {
|
|
193
|
-
newTokens.push(tokens[i]);
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
151
|
+
|
|
152
|
+
if (tokens[i].type === 'dt_open') {
|
|
153
|
+
currentDtIndex = i;
|
|
154
|
+
// Check if this is an empty dt (no content between dt_open and dt_close)
|
|
155
|
+
// An empty dt is when a dt_close token immediately follows a dt_open token
|
|
156
|
+
if (i + 1 < tokens.length && tokens[i + 1].type === 'dt_close') {
|
|
157
|
+
// Mark this dt pair for handling by adding an isEmpty property
|
|
158
|
+
// This property will be used later to skip rendering these empty elements
|
|
159
|
+
tokens[i].isEmpty = true;
|
|
160
|
+
tokens[i + 1].isEmpty = true;
|
|
196
161
|
}
|
|
197
|
-
|
|
198
|
-
// Replace the old tokens with the new sorted ones
|
|
199
|
-
tokens.splice(idx, newTokens.length, ...newTokens);
|
|
200
162
|
}
|
|
201
|
-
// END Sort terms and definitions alphabetically
|
|
202
163
|
}
|
|
203
164
|
|
|
204
|
-
|
|
205
|
-
|
|
165
|
+
// Second pass - add classes and handle last-dd
|
|
166
|
+
// Now that we've identified empty dt elements, we can process the tokens
|
|
167
|
+
// while skipping the empty ones
|
|
206
168
|
for (let i = idx + 1; i < tokens.length; i++) {
|
|
207
169
|
if (tokens[i].type === 'dl_close') {
|
|
208
170
|
// Add class to the last <dd> before closing <dl>
|
|
@@ -219,6 +181,12 @@ module.exports = function (md, templates = {}) {
|
|
|
219
181
|
}
|
|
220
182
|
|
|
221
183
|
if (tokens[i].type === 'dt_open') {
|
|
184
|
+
// Skip empty dt elements - this is where we use the isEmpty flag
|
|
185
|
+
// to avoid processing empty definition terms
|
|
186
|
+
if (tokens[i].isEmpty) {
|
|
187
|
+
continue; // Skip to the next iteration without processing this empty dt
|
|
188
|
+
}
|
|
189
|
+
|
|
222
190
|
// Add class to the last <dd> before a new <dt>
|
|
223
191
|
if (lastDdIndex !== -1) {
|
|
224
192
|
const ddToken = tokens[lastDdIndex];
|
|
@@ -239,4 +207,67 @@ module.exports = function (md, templates = {}) {
|
|
|
239
207
|
|
|
240
208
|
return originalRender(tokens, idx, options, env, self);
|
|
241
209
|
};
|
|
210
|
+
|
|
211
|
+
// Override the rendering of dt elements to properly handle transcluded terms
|
|
212
|
+
const originalDtRender = md.renderer.rules.dt_open || function (tokens, idx, options, env, self) {
|
|
213
|
+
return self.renderToken(tokens, idx, options);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
md.renderer.rules.dt_open = function (tokens, idx, options, env, self) {
|
|
217
|
+
// Skip rendering empty dt elements - this is the first critical fix
|
|
218
|
+
// When a dt has been marked as empty, we return an empty string
|
|
219
|
+
// instead of rendering the <dt> tag. This effectively removes empty dt tags
|
|
220
|
+
// from the output HTML.
|
|
221
|
+
if (tokens[idx].isEmpty) {
|
|
222
|
+
return '';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Check if this dt is part of a transcluded term by looking at the next inline token
|
|
226
|
+
// This is part of the second fix, to properly handle transcluded terms
|
|
227
|
+
let isTranscluded = false;
|
|
228
|
+
for (let i = idx + 1; i < tokens.length; i++) {
|
|
229
|
+
if (tokens[i].type === 'dt_close') {
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
// Look for child tokens that are template tokens with type 'tref'
|
|
233
|
+
// These represent transcluded terms from external sources
|
|
234
|
+
if (tokens[i].type === 'inline' &&
|
|
235
|
+
tokens[i].children &&
|
|
236
|
+
tokens[i].children.some(child =>
|
|
237
|
+
child.type === 'template' &&
|
|
238
|
+
child.info &&
|
|
239
|
+
child.info.type === 'tref')) {
|
|
240
|
+
isTranscluded = true;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Add a class for transcluded terms to ensure proper styling
|
|
246
|
+
// This helps maintain consistent styling for transcluded terms
|
|
247
|
+
if (isTranscluded) {
|
|
248
|
+
const classIndex = tokens[idx].attrIndex('class');
|
|
249
|
+
if (classIndex < 0) {
|
|
250
|
+
tokens[idx].attrPush(['class', 'transcluded-xref-term']);
|
|
251
|
+
} else {
|
|
252
|
+
tokens[idx].attrs[classIndex][1] += ' transcluded-xref-term';
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return originalDtRender(tokens, idx, options, env, self);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// Similarly override dt_close to skip empty dts
|
|
260
|
+
const originalDtCloseRender = md.renderer.rules.dt_close || function (tokens, idx, options, env, self) {
|
|
261
|
+
return self.renderToken(tokens, idx, options);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
md.renderer.rules.dt_close = function (tokens, idx, options, env, self) {
|
|
265
|
+
// Skip rendering the closing </dt> tag for empty dt elements
|
|
266
|
+
// This completes the fix for empty dt elements by ensuring neither
|
|
267
|
+
// the opening nor closing tags are rendered
|
|
268
|
+
if (tokens[idx].isEmpty) {
|
|
269
|
+
return '';
|
|
270
|
+
}
|
|
271
|
+
return originalDtCloseRender(tokens, idx, options, env, self);
|
|
272
|
+
};
|
|
242
273
|
};
|
package/src/prepare-tref.js
CHANGED
|
@@ -26,23 +26,40 @@ const { shouldProcessFile } = require('./utils/file-filter');
|
|
|
26
26
|
|
|
27
27
|
function getLocalXTrefContent(externalSpec, term) {
|
|
28
28
|
const filePath = path.join('output', 'xtrefs-data.json');
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
owner
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
32
|
+
const xtrefs = data.xtrefs;
|
|
33
|
+
|
|
34
|
+
for (const xtref of xtrefs) {
|
|
35
|
+
if (xtref.externalSpec === externalSpec && xtref.term === term) {
|
|
36
|
+
// Validate that required properties exist
|
|
37
|
+
if (!xtref.content || !xtref.owner || !xtref.repo || !xtref.repoUrl) {
|
|
38
|
+
console.warn(`Warning: Incomplete data for ${externalSpec}, ${term}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
content: xtref.content || "No content available",
|
|
43
|
+
commitHash: xtref.commitHash || "Not available",
|
|
44
|
+
owner: xtref.owner || "Unknown",
|
|
45
|
+
repo: xtref.repo || "Unknown",
|
|
46
|
+
repoUrl: xtref.repoUrl || "#",
|
|
47
|
+
avatarUrl: xtref.avatarUrl || ""
|
|
48
|
+
};
|
|
49
|
+
}
|
|
42
50
|
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error(`Error reading xtrefs-data.json: ${err}`);
|
|
43
53
|
}
|
|
44
54
|
|
|
45
|
-
return
|
|
55
|
+
return {
|
|
56
|
+
content: `Term '${term}' not found in external specification '${externalSpec}'`,
|
|
57
|
+
commitHash: "Not available",
|
|
58
|
+
owner: "Unknown",
|
|
59
|
+
repo: "Unknown",
|
|
60
|
+
repoUrl: "#",
|
|
61
|
+
avatarUrl: ""
|
|
62
|
+
};
|
|
46
63
|
}
|
|
47
64
|
|
|
48
65
|
// Function to process markdown files in a directory recursively
|
|
@@ -93,18 +110,34 @@ function prepareTref(directory) {
|
|
|
93
110
|
if (lines[i].startsWith('[[tref:')) {
|
|
94
111
|
const tref = /\[\[tref:(.*?)\]\]/;
|
|
95
112
|
const match = lines[i].match(tref);
|
|
113
|
+
let currentTref = lines[i]; // Store the current tref line for error handling
|
|
114
|
+
|
|
96
115
|
if (match) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
116
|
+
try {
|
|
117
|
+
const result = match[1].split(',').map(term => term.trim());
|
|
118
|
+
|
|
119
|
+
if (result.length < 2) {
|
|
120
|
+
throw new Error(`Invalid tref format. Expected: [[tref:spec,term]], got: ${match[0]}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const localXTrefContent = getLocalXTrefContent(result[0], result[1]);
|
|
124
|
+
|
|
125
|
+
// Skip processing if essential data is missing
|
|
126
|
+
if (!localXTrefContent) {
|
|
127
|
+
console.warn(`Warning: No content found for ${result[0]}, ${result[1]}`);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const defPart = /\[\[def: ([^,]+),.*?\]\]/g;
|
|
132
|
+
if (localXTrefContent.content) {
|
|
133
|
+
localXTrefContent.content = localXTrefContent.content.replace(defPart, '');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const readyForWrite = dedent`
|
|
104
137
|
${match[0]}
|
|
105
138
|
| Property | Value |
|
|
106
139
|
| -------- | ----- |
|
|
107
|
-
| Owner |
|
|
140
|
+
| Owner | ${localXTrefContent.avatarUrl ? `` : ''} ${localXTrefContent.owner} |
|
|
108
141
|
| Repo | [${localXTrefContent.repo}](${localXTrefContent.repoUrl}) |
|
|
109
142
|
| Commit hash | ${localXTrefContent.commitHash} |
|
|
110
143
|
|
|
@@ -115,12 +148,16 @@ ${contentAfterSpan}
|
|
|
115
148
|
|
|
116
149
|
`;
|
|
117
150
|
|
|
118
|
-
|
|
151
|
+
fs.writeFileSync(itemPath, readyForWrite, 'utf8');
|
|
152
|
+
} catch (err) {
|
|
153
|
+
console.error(`Error processing tref: ${err}`);
|
|
154
|
+
fs.writeFileSync(itemPath, currentTref + '\n\n' + '\n\nError processing reference: ' + err.message, 'utf8');
|
|
155
|
+
}
|
|
119
156
|
}
|
|
120
157
|
}
|
|
121
158
|
}
|
|
122
159
|
} catch (err) {
|
|
123
|
-
|
|
160
|
+
console.error(`Error processing file ${itemPath}: ${err}`);
|
|
124
161
|
}
|
|
125
162
|
}
|
|
126
163
|
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions to fetch and parse various JSON specification files
|
|
3
|
+
*/
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Fetches the output/specs-generated.json file and returns it as a JavaScript object
|
|
9
|
+
* @returns {Object} The parsed contents of specs-generated.json
|
|
10
|
+
*/
|
|
11
|
+
function fetchSpecs() {
|
|
12
|
+
try {
|
|
13
|
+
// Resolve path to output/specs-generated.json from the project root
|
|
14
|
+
const specsPath = path.resolve(process.cwd(), 'output', 'specs-generated.json');
|
|
15
|
+
|
|
16
|
+
// Read the file synchronously
|
|
17
|
+
const specsContent = fs.readFileSync(specsPath, 'utf8');
|
|
18
|
+
|
|
19
|
+
// Parse the JSON content
|
|
20
|
+
const specs = JSON.parse(specsContent);
|
|
21
|
+
|
|
22
|
+
return specs;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('Error fetching output/specs-generated.json:', error.message);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Fetches the output/xtrefs-data.json file and returns it as a JavaScript object
|
|
31
|
+
* @returns {Object} The parsed contents of xtrefs-data.json
|
|
32
|
+
*/
|
|
33
|
+
function fetchExternalTerms() {
|
|
34
|
+
try {
|
|
35
|
+
// Resolve path to output/xtrefs-data.json from the project root
|
|
36
|
+
const xtrefsPath = path.resolve(process.cwd(), 'output', 'xtrefs-data.json');
|
|
37
|
+
|
|
38
|
+
// Read the file synchronously
|
|
39
|
+
const xtrefsContent = fs.readFileSync(xtrefsPath, 'utf8');
|
|
40
|
+
|
|
41
|
+
// Parse the JSON content
|
|
42
|
+
const xtrefs = JSON.parse(xtrefsContent);
|
|
43
|
+
|
|
44
|
+
return xtrefs;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('Error fetching output/xtrefs-data.json:', error.message);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Asynchronous version of fetchGeneratedSpecs
|
|
53
|
+
* @returns {Promise<Object>} The parsed specs-generated object
|
|
54
|
+
*/
|
|
55
|
+
async function fetchSpecsAsync() {
|
|
56
|
+
try {
|
|
57
|
+
// Resolve path to output/specs-generated.json from the project root
|
|
58
|
+
const specsPath = path.resolve(process.cwd(), 'output', 'specs-generated.json');
|
|
59
|
+
|
|
60
|
+
// Read the file asynchronously
|
|
61
|
+
const specsContent = await fs.promises.readFile(specsPath, 'utf8');
|
|
62
|
+
|
|
63
|
+
// Parse the JSON content
|
|
64
|
+
const specs = JSON.parse(specsContent);
|
|
65
|
+
|
|
66
|
+
return specs;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error('Error fetching output/specs-generated.json:', error.message);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Asynchronous version of fetchXtrefsData
|
|
75
|
+
* @returns {Promise<Object>} The parsed xtrefs-data object
|
|
76
|
+
*/
|
|
77
|
+
async function fetchExternalTermsAsync() {
|
|
78
|
+
try {
|
|
79
|
+
// Resolve path to output/xtrefs-data.json from the project root
|
|
80
|
+
const xtrefsPath = path.resolve(process.cwd(), 'output', 'xtrefs-data.json');
|
|
81
|
+
|
|
82
|
+
// Read the file asynchronously
|
|
83
|
+
const xtrefsContent = await fs.promises.readFile(xtrefsPath, 'utf8');
|
|
84
|
+
|
|
85
|
+
// Parse the JSON content
|
|
86
|
+
const xtrefs = JSON.parse(xtrefsContent);
|
|
87
|
+
|
|
88
|
+
return xtrefs;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('Error fetching output/xtrefs-data.json:', error.message);
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
fetchSpecs,
|
|
97
|
+
fetchSpecsAsync,
|
|
98
|
+
fetchExternalTerms,
|
|
99
|
+
fetchExternalTermsAsync
|
|
100
|
+
};
|
package/templates/template.html
CHANGED
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
|
|
110
110
|
<header id="header" class="navbar sticky-top p-0 shadow">
|
|
111
111
|
<!-- Left-aligned elements -->
|
|
112
|
-
<button class="nav-link px-3 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu"
|
|
112
|
+
<button class="nav-link d-print-none px-3 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu"
|
|
113
113
|
aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
|
|
114
114
|
<svg class="bi">
|
|
115
115
|
<use xlink:href="#list" />
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
</button>
|
|
118
118
|
|
|
119
119
|
<a id="logo" href="${specLogoLink}">
|
|
120
|
-
<img class="m-1" src="${specLogo}" alt="" />
|
|
120
|
+
<img class="d-print-none m-1" src="${specLogo}" alt="" />
|
|
121
121
|
</a>
|
|
122
122
|
<!-- <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 fs-6 text-white" href="#">Spec-Up-T</a> -->
|
|
123
123
|
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
<div class="flex-grow-1"></div>
|
|
126
126
|
|
|
127
127
|
<!-- Right-aligned elements -->
|
|
128
|
-
<div class="d-flex align-items-center">
|
|
128
|
+
<div class="d-flex align-items-center service-menu d-print-none">
|
|
129
129
|
|
|
130
130
|
<!-- Settings side menu -->
|
|
131
131
|
<button id="repo_settings" animate class="btn btn-sm btn-outline-secondary ms-2" type="button"
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
</button>
|
|
138
138
|
|
|
139
139
|
<!-- Dark / Light theme selector -->
|
|
140
|
-
<div class="dropdown bd-mode-toggle
|
|
140
|
+
<div class="dropdown bd-mode-toggle">
|
|
141
141
|
<button
|
|
142
142
|
class="btn btn-bd-primary btn-sm btn-outline-secondary dropdown-toggle d-flex align-items-center"
|
|
143
143
|
id="bd-theme" type="button" aria-expanded="false" data-bs-toggle="dropdown"
|
|
@@ -175,13 +175,18 @@
|
|
|
175
175
|
</ul>
|
|
176
176
|
</div>
|
|
177
177
|
|
|
178
|
+
<!-- Container width toggle -->
|
|
179
|
+
<button id="container_toggle" title="Toggle wide/narrow layout" type="button" class="btn btn-sm btn-outline-secondary me-2">
|
|
180
|
+
<span class="visually-hidden">Toggle wide/narrow layout</span>
|
|
181
|
+
<i class="bi bi-arrows-angle-expand"></i>
|
|
182
|
+
</button>
|
|
183
|
+
|
|
178
184
|
<!-- Font size -->
|
|
179
185
|
<div class="adjust-font-size btn-group me-2" role="group">
|
|
180
186
|
<button title="Decrease font size" type="button"
|
|
181
187
|
class="btn btn-outline-secondary m-0 border-end-0" id="decreaseBtn"><span
|
|
182
188
|
class="visually-hidden">Decrease font size</span>
|
|
183
189
|
</button>
|
|
184
|
-
<!-- <button type="button" class="btn btn-sm btn-outline-secondary m-0 px-2" id="resetBtn">0</button> -->
|
|
185
190
|
<button title="Increase font size" type="button"
|
|
186
191
|
class="btn btn-outline-secondary m-0 border-start-0" id="increaseBtn">
|
|
187
192
|
<span class="visually-hidden">Increase font size</span>
|
|
@@ -192,7 +197,7 @@
|
|
|
192
197
|
|
|
193
198
|
<div class="container">
|
|
194
199
|
<div class="row">
|
|
195
|
-
<div class="sidebar border border-right col-md-4 col-lg-3 bg-body-tertiary">
|
|
200
|
+
<div class="sidebar d-print-none border border-right col-md-4 col-lg-3 bg-body-tertiary">
|
|
196
201
|
<div class="offcanvas-md offcanvas-start bg-body-tertiary p-2 pt-5" tabindex="-1" id="sidebarMenu"
|
|
197
202
|
aria-labelledby="sidebarMenuLabel">
|
|
198
203
|
<div class="offcanvas-header">
|
|
@@ -210,7 +215,7 @@
|
|
|
210
215
|
|
|
211
216
|
<main class="col-md-8 ms-sm-auto col-lg-9 px-md-4 pt-5">
|
|
212
217
|
<article id="content" class="">
|
|
213
|
-
<div id="terminology-section-utility-container" class="alert alert-primary p-3"></div>
|
|
218
|
+
<div id="terminology-section-utility-container" class="d-print-none alert alert-primary p-3"></div>
|
|
214
219
|
${render}
|
|
215
220
|
</article>
|
|
216
221
|
|
package/assets/js/css-helper.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
JS to help with CSS.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
function addClassToTranscludedTerms() {
|
|
6
|
-
// Find all spans with class 'transcluded-xref-term'
|
|
7
|
-
const spans = document.querySelectorAll('span.transcluded-xref-term');
|
|
8
|
-
|
|
9
|
-
spans.forEach(span => {
|
|
10
|
-
// Find the closest <dt> ancestor
|
|
11
|
-
const dt = span.closest('dt');
|
|
12
|
-
if (dt) {
|
|
13
|
-
// Add class 'transcluded-xref-term' to the <dt>
|
|
14
|
-
dt.classList.add('transcluded-xref-term');
|
|
15
|
-
|
|
16
|
-
// Get the next sibling elements until the next <dt> or </dl>
|
|
17
|
-
let sibling = dt.nextElementSibling;
|
|
18
|
-
while (sibling && sibling.tagName !== 'DT' && sibling.tagName !== 'DL') {
|
|
19
|
-
if (sibling.tagName === 'DD') {
|
|
20
|
-
sibling.classList.add('transcluded-xref-term');
|
|
21
|
-
}
|
|
22
|
-
sibling = sibling.nextElementSibling;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
document.addEventListener("DOMContentLoaded", function () {
|
|
29
|
-
addClassToTranscludedTerms();
|
|
30
|
-
});
|