spec-up-t 1.2.9 → 1.3.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.
Files changed (32) hide show
  1. package/.github/copilot-instructions.md +2 -1
  2. package/assets/compiled/body.js +5 -5
  3. package/assets/compiled/head.css +1 -0
  4. package/assets/css/counter.css +104 -0
  5. package/assets/js/addAnchorsToTerms.js +13 -5
  6. package/assets/js/collapse-definitions.js +0 -3
  7. package/assets/js/custom-elements.js +25 -27
  8. package/assets/js/fix-last-dd.js +6 -3
  9. package/assets/js/highlight-heading-plus-sibling-nodes.js +0 -1
  10. package/assets/js/highlight-heading-plus-sibling-nodes.test.js +120 -0
  11. package/assets/js/insert-trefs.js +32 -28
  12. package/config/asset-map.json +1 -0
  13. package/index.js +33 -227
  14. package/package.json +4 -2
  15. package/sonar-project.properties +7 -0
  16. package/src/collect-external-references.js +22 -11
  17. package/src/collect-external-references.test.js +153 -2
  18. package/src/collectExternalReferences/fetchTermsFromIndex.js +65 -110
  19. package/src/collectExternalReferences/processXTrefsData.js +9 -11
  20. package/src/create-docx.js +332 -0
  21. package/src/create-pdf.js +243 -122
  22. package/src/fix-markdown-files.js +31 -34
  23. package/src/html-dom-processor.js +290 -0
  24. package/src/init.js +3 -0
  25. package/src/install-from-boilerplate/boilerplate/.github/workflows/menu.yml +51 -36
  26. package/src/install-from-boilerplate/boilerplate/spec/example-markup-in-markdown.md +0 -1
  27. package/src/install-from-boilerplate/boilerplate/spec/terms-and-definitions-intro.md +1 -5
  28. package/src/install-from-boilerplate/config-scripts-keys.js +4 -4
  29. package/src/install-from-boilerplate/menu.sh +6 -6
  30. package/src/markdown-it-extensions.js +54 -33
  31. package/src/references.js +18 -6
  32. package/templates/template.html +2 -0
@@ -0,0 +1,290 @@
1
+ 'use strict';
2
+
3
+ const { JSDOM } = require('jsdom');
4
+
5
+ /**
6
+ * Sorts definition terms in HTML alphabetically (case-insensitive)
7
+ *
8
+ * @param {string} html - The HTML content to process
9
+ * @returns {string} - The HTML with sorted definition terms
10
+ */
11
+ function sortDefinitionTermsInHtml(html) {
12
+ const dom = new JSDOM(html);
13
+ const document = dom.window.document;
14
+
15
+ // Find the terms and definitions list
16
+ const dlElement = document.querySelector('.terms-and-definitions-list');
17
+ if (!dlElement) return html; // If not found, return the original HTML
18
+
19
+ // Collect all dt/dd pairs
20
+ const pairs = [];
21
+ let currentDt = null;
22
+ let currentDds = [];
23
+
24
+ // Process each child of the dl element
25
+ Array.from(dlElement.children).forEach(child => {
26
+ if (child.tagName === 'DT') {
27
+ // If we already have a dt, save the current pair
28
+ if (currentDt) {
29
+ pairs.push({
30
+ dt: currentDt,
31
+ dds: [...currentDds],
32
+ text: currentDt.textContent.trim().toLowerCase() // Use lowercase for sorting
33
+ });
34
+ currentDds = []; // Reset dds for the next dt
35
+ }
36
+ currentDt = child;
37
+ } else if (child.tagName === 'DD' && currentDt) {
38
+ currentDds.push(child);
39
+ }
40
+ });
41
+
42
+ // Add the last pair if exists
43
+ if (currentDt) {
44
+ pairs.push({
45
+ dt: currentDt,
46
+ dds: [...currentDds],
47
+ text: currentDt.textContent.trim().toLowerCase()
48
+ });
49
+ }
50
+
51
+ // Sort pairs case-insensitively
52
+ pairs.sort((a, b) => a.text.localeCompare(b.text));
53
+
54
+ // Clear the dl element
55
+ while (dlElement.firstChild) {
56
+ dlElement.removeChild(dlElement.firstChild);
57
+ }
58
+
59
+ // Re-append elements in sorted order
60
+ pairs.forEach(pair => {
61
+ dlElement.appendChild(pair.dt);
62
+ pair.dds.forEach(dd => {
63
+ dlElement.appendChild(dd);
64
+ });
65
+ });
66
+
67
+ // Return the modified HTML
68
+ return dom.serialize();
69
+ }
70
+
71
+ /**
72
+ * Fixes broken definition list (dl) structures in the HTML output.
73
+ * Specifically, it addresses the issue where transcluded terms (tref tags) break
74
+ * out of the definition list, creating separate lists instead of a continuous one.
75
+ *
76
+ * The strategy:
77
+ * 1. Find all definition lists (dl elements) in the document
78
+ * 2. Use the dl with class 'terms-and-definitions-list' as the main/target list
79
+ * 3. Process each subsequent node after the this main dl:
80
+ * - If another dl is found, merge all its children into the main dl
81
+ * - If a standalone dt is found, move it and its associated dd elements into the main dl
82
+ * - Remove any empty paragraphs that might be breaking the list continuity
83
+ *
84
+ * This ensures all terms appear in one continuous definition list,
85
+ * regardless of how they were originally rendered in the markdown.
86
+ *
87
+ * @param {string} html - The HTML content to fix
88
+ * @returns {string} - The fixed HTML content with merged definition lists
89
+ */
90
+ function fixDefinitionListStructure(html) {
91
+ const dom = new JSDOM(html);
92
+ const document = dom.window.document;
93
+
94
+ // Find all dl elements first
95
+ const allDls = Array.from(document.querySelectorAll('dl'));
96
+
97
+ // Then filter to find the one with the terms-and-definitions-list class
98
+ const dlElements = allDls.filter(dl => {
99
+ return dl?.classList?.contains('terms-and-definitions-list');
100
+ });
101
+
102
+ // Find any transcluded term dt elements anywhere in the document
103
+ const transcludedTerms = document.querySelectorAll('dt.transcluded-xref-term');
104
+
105
+ let mainDl = null;
106
+
107
+ // If we have an existing dl with the terms-and-definitions-list class, use it
108
+ if (dlElements.length > 0) {
109
+ mainDl = dlElements[0]; // Use the first one
110
+ }
111
+ // If we have transcluded terms but no main dl, we need to create one
112
+ else if (transcludedTerms.length > 0) {
113
+ // Create a new dl element with the right class
114
+ mainDl = document.createElement('dl');
115
+ mainDl.className = 'terms-and-definitions-list';
116
+
117
+ // Look for the marker
118
+ const marker = document.getElementById('terminology-section-start');
119
+
120
+ if (marker) {
121
+ // Insert the new dl right after the marker
122
+ if (marker.nextSibling) {
123
+ marker.parentNode.insertBefore(mainDl, marker.nextSibling);
124
+ } else {
125
+ marker.parentNode.appendChild(mainDl);
126
+ }
127
+ } else {
128
+ // Fallback to the original approach if marker isn't found
129
+ const firstTerm = transcludedTerms[0];
130
+ const insertPoint = firstTerm.parentNode;
131
+ insertPoint.parentNode.insertBefore(mainDl, insertPoint);
132
+ }
133
+ }
134
+
135
+ // Safety check - if we still don't have a mainDl, exit early to avoid null reference errors
136
+ if (!mainDl) {
137
+ return html; // Return the original HTML without modifications
138
+ }
139
+
140
+ /**
141
+ * Helper function to collect dt/dd pairs from a node
142
+ * @param {Node} startNode - The node to start collecting from
143
+ * @returns {Array} - Array of elements that are part of the definition group
144
+ */
145
+ function collectDtDdGroup(startNode) {
146
+ const group = [];
147
+ let currentNode = startNode;
148
+
149
+ // Collect the dt and all following dd elements
150
+ while (currentNode && (currentNode.tagName === 'DT' || currentNode.tagName === 'DD')) {
151
+ group.push(currentNode);
152
+ currentNode = currentNode.nextSibling;
153
+
154
+ // Skip text nodes (whitespace) between elements
155
+ while (currentNode && currentNode.nodeType === 3 && !currentNode.textContent.trim()) {
156
+ currentNode = currentNode.nextSibling;
157
+ }
158
+ }
159
+
160
+ return group;
161
+ }
162
+
163
+ // Process all transcluded terms and move them with their dd elements
164
+ transcludedTerms.forEach(dt => {
165
+ // Check if this dt is not already inside our main dl
166
+ if (dt.parentElement !== mainDl) {
167
+ // Collect the dt and its associated dd elements
168
+ const group = collectDtDdGroup(dt);
169
+
170
+ // Move all elements in the group to the main dl
171
+ group.forEach(element => {
172
+ if (element.parentNode) {
173
+ const elementClone = element.cloneNode(true);
174
+ mainDl.appendChild(elementClone);
175
+ element.parentNode.removeChild(element);
176
+ }
177
+ });
178
+ }
179
+ });
180
+
181
+ // Remove any empty dt elements that may exist
182
+ const emptyDts = mainDl.querySelectorAll('dt:empty');
183
+ emptyDts.forEach(emptyDt => {
184
+ emptyDt.parentNode.removeChild(emptyDt);
185
+ });
186
+
187
+ // Process all subsequent content after the main dl
188
+ let currentNode = mainDl.nextSibling;
189
+
190
+ // Process all subsequent content
191
+ while (currentNode) {
192
+ // Save the next node before potentially modifying the DOM
193
+ let nextNode = currentNode.nextSibling;
194
+
195
+ // Handle different node types
196
+ if (currentNode.nodeType === 1) { // 1 = Element node
197
+ if (currentNode.tagName === 'DL') {
198
+ // Check if this is a reference list (contains dt elements with id="ref:...")
199
+ const hasRefIds = currentNode.innerHTML.includes('id="ref:') ||
200
+ currentNode.classList.contains('reference-list');
201
+
202
+ if (!hasRefIds) {
203
+ // Only move non-reference definition lists - move all its children to the main dl
204
+ while (currentNode.firstChild) {
205
+ mainDl.appendChild(currentNode.firstChild);
206
+ }
207
+ // Remove the now-empty dl element
208
+ currentNode.parentNode.removeChild(currentNode);
209
+ }
210
+ // If it's a reference list, leave it alone
211
+ }
212
+ else if (currentNode.tagName === 'DT') {
213
+ // Check if this dt has a ref: id (spec reference)
214
+ const hasRefId = currentNode.id?.startsWith('ref:');
215
+
216
+ if (!hasRefId) {
217
+ // Collect the dt and its associated dd elements
218
+ const group = collectDtDdGroup(currentNode);
219
+
220
+ // Move all elements in the group to the main dl
221
+ group.forEach(element => {
222
+ if (element.parentNode) {
223
+ const elementClone = element.cloneNode(true);
224
+ mainDl.appendChild(elementClone);
225
+ element.parentNode.removeChild(element);
226
+ }
227
+ });
228
+
229
+ // Skip the nodes we just processed
230
+ let skipNodes = group.length - 1; // -1 because currentNode will be advanced anyway
231
+ while (skipNodes > 0 && nextNode) {
232
+ const nodeToSkip = nextNode;
233
+ currentNode = nextNode;
234
+ nextNode = nextNode.nextSibling;
235
+ skipNodes--;
236
+ }
237
+ }
238
+ // If it's a spec reference dt, leave it alone
239
+ }
240
+ else if (currentNode.tagName === 'DD') {
241
+ // Handle orphaned dd elements - move them to the main dl if they don't belong to a reference
242
+ const dtBefore = currentNode.previousSibling;
243
+ let hasAssociatedDt = false;
244
+
245
+ // Check if there's a dt before this dd (walking backwards through siblings)
246
+ let checkNode = currentNode.previousSibling;
247
+ while (checkNode) {
248
+ // Skip text nodes
249
+ if (checkNode.nodeType === 3 && !checkNode.textContent.trim()) {
250
+ checkNode = checkNode.previousSibling;
251
+ continue;
252
+ }
253
+
254
+ if (checkNode.tagName === 'DT') {
255
+ hasAssociatedDt = true;
256
+ break;
257
+ } else if (checkNode.tagName !== 'DD') {
258
+ // Found a non-dt, non-dd element, so this dd is orphaned
259
+ break;
260
+ }
261
+
262
+ checkNode = checkNode.previousSibling;
263
+ }
264
+
265
+ // If this dd doesn't have an associated dt in the same context, move it to main dl
266
+ if (!hasAssociatedDt) {
267
+ const ddClone = currentNode.cloneNode(true);
268
+ mainDl.appendChild(ddClone);
269
+ currentNode.parentNode.removeChild(currentNode);
270
+ }
271
+ }
272
+ else if (currentNode.tagName === 'P' &&
273
+ (!currentNode.textContent || currentNode.textContent.trim() === '')) {
274
+ // Remove empty paragraphs - these break the list structure
275
+ currentNode.parentNode.removeChild(currentNode);
276
+ }
277
+ }
278
+
279
+ // Move to the next node we saved earlier
280
+ currentNode = nextNode;
281
+ }
282
+
283
+ // Return the fixed HTML
284
+ return dom.serialize();
285
+ }
286
+
287
+ module.exports = {
288
+ sortDefinitionTermsInHtml,
289
+ fixDefinitionListStructure
290
+ };
package/src/init.js CHANGED
@@ -5,6 +5,9 @@ const initFlagPath = path.join(outputDir, 'init.flag');
5
5
 
6
6
  async function initialize() {
7
7
  try {
8
+ // Ensure the .cache directory exists
9
+ await fs.ensureDir(outputDir);
10
+
8
11
  // Check if the init script has already run
9
12
  if (await fs.pathExists(initFlagPath)) {
10
13
  return;
@@ -9,17 +9,16 @@ on:
9
9
  required: true
10
10
  default: 'Render specification'
11
11
  options:
12
- # - Edit specification
12
+ - Add content
13
13
  - Render specification
14
- # - Develop specification
15
- - Collect external references (cached)
16
- - Collect external references (no cache)
17
- - Convert to PDF
14
+ - Export to PDF
15
+ - Export to DOCX
16
+ - Collect external references
17
+ - Add, remove or view xref source
18
+ - Configure
19
+ - Run health check
20
+ - Open documentation website
18
21
  - Freeze specification
19
- # - List references
20
- # - Show help
21
- # - Add/remove xref source
22
- # - Configure specification
23
22
  - Custom update
24
23
 
25
24
  jobs:
@@ -60,9 +59,11 @@ jobs:
60
59
  MY_PAT: ${{ secrets.MY_PAT }} # Make the secret available as an env var
61
60
  run: |
62
61
  case "${{ github.event.inputs.script }}" in
63
- # "Edit specification")
64
- # node -e "require('spec-up-t')()"
65
- # ;;
62
+ "Add content")
63
+ echo "You can start adding your content to the markdown files in the 'spec' directory."
64
+ echo "You can do this by editing local files in an editor or by going to your repository on GitHub."
65
+ echo "More info: https://blockchainbird.github.io/spec-up-t-website/docs/various-roles/content-authors-guide/introduction"
66
+ ;;
66
67
  "Render specification")
67
68
  node --no-warnings -e "require('spec-up-t/index.js')({ nowatch: true })"
68
69
  git config --global user.email "actions@github.com"
@@ -71,31 +72,29 @@ jobs:
71
72
  git commit -m "Render specification: Update files" || echo "No changes to commit"
72
73
  git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
73
74
  ;;
74
- # "Develop specification")
75
- # node -e "require('spec-up-t')({ dev: true })"
76
- # ;;
77
- "Collect external references (cached)")
78
- node --no-warnings -e "require('spec-up-t/src/collect-external-references.js').collectExternalReferences({cache: true})"
75
+ # ...existing code...
76
+ "Export to DOCX")
77
+ node -e "require('spec-up-t/src/create-docx.js')"
79
78
  git config --global user.email "actions@github.com"
80
79
  git config --global user.name "GitHub Actions"
81
80
  git add .
82
- git commit -m "Collect external references (cached)" || echo "No changes to commit"
81
+ git commit -m "Export to DOCX" || echo "No changes to commit"
83
82
  git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
84
83
  ;;
85
- "Collect external references (no cache)")
86
- node --no-warnings -e "require('spec-up-t/src/collect-external-references.js').collectExternalReferences({cache: false, pat: process.env.MY_PAT})"
84
+ "Collect external references")
85
+ node --no-warnings -e "require('spec-up-t/src/collect-external-references.js').collectExternalReferences({ pat: process.env.MY_PAT })"
87
86
  git config --global user.email "actions@github.com"
88
87
  git config --global user.name "GitHub Actions"
89
88
  git add .
90
- git commit -m "Collect external references (no cache)" || echo "No changes to commit"
89
+ git commit -m "Collect external references" || echo "No changes to commit"
91
90
  git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
92
91
  ;;
93
- "Convert to PDF")
92
+ "Export to PDF")
94
93
  node -e "require('spec-up-t/src/create-pdf.js')"
95
94
  git config --global user.email "actions@github.com"
96
95
  git config --global user.name "GitHub Actions"
97
96
  git add .
98
- git commit -m "Convert to PDF" || echo "No changes to commit"
97
+ git commit -m "Export to PDF" || echo "No changes to commit"
99
98
  git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
100
99
  ;;
101
100
  "Freeze specification")
@@ -106,18 +105,34 @@ jobs:
106
105
  git commit -m "Freeze specification" || echo "No changes to commit"
107
106
  git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
108
107
  ;;
109
- # "List references")
110
- # node -e "require('spec-up-t/src/references.js')"
111
- # ;;
112
- # "Show help")
113
- # cat ./node_modules/spec-up-t/src/install-from-boilerplate/help.txt || echo "Help file not found"
114
- # ;;
115
- # "Add/remove xref source")
116
- # node --no-warnings -e "require('spec-up-t/src/add-remove-xref-source.js')"
117
- # ;;
118
- # "Configure specification")
119
- # node --no-warnings -e "require('spec-up-t/src/configure.js')"
120
- # ;;
108
+ "Add, remove or view xref source")
109
+ node --no-warnings -e "require('spec-up-t/src/add-remove-xref-source.js')"
110
+ git config --global user.email "actions@github.com"
111
+ git config --global user.name "GitHub Actions"
112
+ git add .
113
+ git commit -m "Add, remove or view xref source" || echo "No changes to commit"
114
+ git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
115
+ ;;
116
+ "Configure")
117
+ node --no-warnings -e "require('spec-up-t/src/configure.js')"
118
+ git config --global user.email "actions@github.com"
119
+ git config --global user.name "GitHub Actions"
120
+ git add .
121
+ git commit -m "Configure" || echo "No changes to commit"
122
+ git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
123
+ ;;
124
+ "Run health check")
125
+ node --no-warnings -e "require('spec-up-t/src/health-check.js')"
126
+ git config --global user.email "actions@github.com"
127
+ git config --global user.name "GitHub Actions"
128
+ git add .
129
+ git commit -m "Run health check" || echo "No changes to commit"
130
+ git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:main
131
+ ;;
132
+ "Open documentation website")
133
+ echo "Opening documentation website: https://blockchainbird.github.io/spec-up-t-website/"
134
+ echo "Please visit the URL manually: https://blockchainbird.github.io/spec-up-t-website/"
135
+ ;;
121
136
  "Custom update")
122
137
  npm update && node -e "require('spec-up-t/src/install-from-boilerplate/custom-update.js')"
123
138
  git config --global user.email "actions@github.com"
@@ -133,7 +148,7 @@ jobs:
133
148
  esac
134
149
 
135
150
  - name: Deploy to GitHub Pages
136
- if: success() && github.event.inputs.script != 'Show help' && github.event.inputs.script != 'Show menu'
151
+ if: success() && github.event.inputs.script != 'Add content' && github.event.inputs.script != 'Open documentation website' && github.event.inputs.script != 'Configure' && github.event.inputs.script != 'Run health check'
137
152
  uses: peaceiris/actions-gh-pages@v3.7.3
138
153
  with:
139
154
  github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -159,7 +159,6 @@ You can even insert content within more complex blocks, like the JSON object bel
159
159
  | ♙ | ♙ | ♙ | ♙ | | ♙ | ♙ | ♙ |
160
160
  | ♖ | ♘ | ♗ | ♕ | ♔ | | | ♖ |
161
161
 
162
-
163
162
  ### Sequence Diagrams
164
163
 
165
164
  <pre>
@@ -1,5 +1 @@
1
- # Terms and Definitions Intro
2
-
3
- ## Demo terms, definitions and external definitions
4
-
5
- A demo of terms and definitions, and references to external definitions.
1
+ [//]: # (This file, named “terms-and-definitions-intro.md” is mandatory and should not be deleted.)
@@ -2,9 +2,9 @@ const configScriptsKeys = {
2
2
  "edit": "node -e \"require('spec-up-t')()\"",
3
3
  "render": "node --no-warnings -e \"require('spec-up-t/index.js')({ nowatch: true })\"",
4
4
  "dev": "node -e \"require('spec-up-t')({ dev: true })\"",
5
- "collectExternalReferencesCache": "node --no-warnings -e \"require('spec-up-t/src/collect-external-references.js').collectExternalReferences({cache: true})\"",
6
- "collectExternalReferencesNoCache": "node --no-warnings -e \"require('spec-up-t/src/collect-external-references.js').collectExternalReferences({cache: false})\"",
5
+ "collectExternalReferences": "node --no-warnings -e \"require('spec-up-t/src/collect-external-references.js').collectExternalReferences()\"",
7
6
  "topdf": "node -e \"require('spec-up-t/src/create-pdf.js')\"",
7
+ "todocx": "node -e \"require('spec-up-t/src/create-docx.js')\"",
8
8
  "freeze": "node -e \"require('spec-up-t/src/freeze.js')\"",
9
9
  "references": "node -e \"require('spec-up-t/src/references.js')\"",
10
10
  "help": "cat ./node_modules/spec-up-t/src/install-from-boilerplate/help.txt",
@@ -20,9 +20,9 @@ const configOverwriteScriptsKeys = {
20
20
  "edit": true,
21
21
  "render": true,
22
22
  "dev": true,
23
- "collectExternalReferencesCache": true,
24
- "collectExternalReferencesNoCache": true,
23
+ "collectExternalReferences": true,
25
24
  "topdf": true,
25
+ "todocx": true,
26
26
  "freeze": true,
27
27
  "references": true,
28
28
  "help": true,
@@ -6,8 +6,8 @@ function handle_choice() {
6
6
  "Add content" "do_add_content"
7
7
  "Render specification" "do_render"
8
8
  "Export to PDF" "do_topdf"
9
- "Collect external references (cache, faster)" "collect_external_references_cache"
10
- "Collect external references (no cache, slower)" "collect_external_references_no_cache"
9
+ "Export to DOCX" "do_todocx"
10
+ "Collect external references" "collect_external_references"
11
11
  "Add, remove or view xref source" "do_add_remove_xref_source"
12
12
  "Configure" "do_configure"
13
13
  "Run health check" "do_health_check"
@@ -47,8 +47,8 @@ function display_intro() {
47
47
  [0] Add content
48
48
  [1] Render specification
49
49
  [2] Export to PDF
50
- [3] Collect external references (cache, faster)
51
- [4] Collect external references (no cache, slower)
50
+ [3] Export to DOCX
51
+ [4] Collect external references
52
52
  [5] Add, remove or view xref source
53
53
  [6] Configure
54
54
  [7] Run health check
@@ -74,8 +74,8 @@ function do_add_content() {
74
74
 
75
75
  function do_render() { clear; npm run render; }
76
76
  function do_topdf() { clear; npm run topdf; }
77
- function collect_external_references_cache() { clear; npm run collectExternalReferencesCache; }
78
- function collect_external_references_no_cache() { clear; npm run collectExternalReferencesNoCache; }
77
+ function do_todocx() { clear; npm run todocx; }
78
+ function collect_external_references() { clear; npm run collectExternalReferences; }
79
79
  function do_add_remove_xref_source() { clear; npm run addremovexrefsource; }
80
80
  function do_configure() { clear; npm run configure; }
81
81
  function do_health_check() { clear; npm run healthCheck; }
@@ -66,12 +66,12 @@ module.exports = function (md, templates = {}) {
66
66
  md.inline.ruler.after('emphasis', 'templates', function templates_ruler(state, silent) {
67
67
  // Get the current parsing position
68
68
  var start = state.pos;
69
-
69
+
70
70
  // Check if we're at an escaped placeholder - if so, skip processing
71
71
  if (state.src.slice(start, start + ESCAPED_PLACEHOLDER.length) === ESCAPED_PLACEHOLDER) {
72
72
  return false;
73
73
  }
74
-
74
+
75
75
  // Check if we're at a template opening marker
76
76
  let prefix = state.src.slice(start, start + levels);
77
77
  if (prefix !== openString) return false;
@@ -203,24 +203,6 @@ module.exports = function (md, templates = {}) {
203
203
  }
204
204
  }
205
205
 
206
- /**
207
- * Helper function to add a 'last-dd' class to a dd token
208
- * This enables special styling for the last definition description in a group
209
- *
210
- * @param {Array} tokens - The token array containing the dd token
211
- * @param {Number} ddIndex - The index of the dd_open token to modify
212
- */
213
- function addLastDdClass(tokens, ddIndex) {
214
- if (ddIndex === -1) return;
215
-
216
- const ddToken = tokens[ddIndex];
217
- const classIndex = ddToken.attrIndex('class');
218
- if (classIndex < 0) {
219
- ddToken.attrPush(['class', 'last-dd']);
220
- } else {
221
- ddToken.attrs[classIndex][1] += ' last-dd';
222
- }
223
- }
224
206
 
225
207
  /**
226
208
  * Helper function to process definition description elements
@@ -232,23 +214,47 @@ module.exports = function (md, templates = {}) {
232
214
  function processLastDdElements(tokens, startIdx) {
233
215
  let lastDdIndex = -1; // Tracks the most recent dd_open token
234
216
 
217
+ }
218
+
219
+ /**
220
+ * Helper function to check if a definition list contains spec references
221
+ * Spec references have dt elements with id attributes starting with "ref:"
222
+ *
223
+ * @param {Array} tokens - The token array to search through
224
+ * @param {Number} startIdx - The index to start searching from (after dl_open)
225
+ * @return {Boolean} True if the dl contains spec references, false otherwise
226
+ */
227
+ function containsSpecReferences(tokens, startIdx) {
235
228
  for (let i = startIdx; i < tokens.length; i++) {
236
229
  if (tokens[i].type === 'dl_close') {
237
- // Add class to the last <dd> before closing the entire <dl>
238
- addLastDdClass(tokens, lastDdIndex);
239
- break;
230
+ break; // Stop when we reach the end of this definition list
240
231
  }
241
-
242
- if (tokens[i].type === 'dt_open' && !tokens[i].isEmpty) {
243
- // When we find a non-empty dt, mark the previous dd as the last one in its group
244
- addLastDdClass(tokens, lastDdIndex);
245
- lastDdIndex = -1; // Reset for the next group
232
+ if (isDtRef(tokens[i])) {
233
+ return true;
246
234
  }
247
-
248
- if (tokens[i].type === 'dd_open') {
249
- lastDdIndex = i; // Track the most recently seen dd_open
235
+ if (isHtmlRef(tokens[i])) {
236
+ return true;
237
+ }
238
+ if (isInlineRef(tokens[i])) {
239
+ return true;
250
240
  }
251
241
  }
242
+ return false;
243
+ }
244
+
245
+ function isDtRef(token) {
246
+ if (token.type !== 'dt_open' || !token.attrs) return false;
247
+ return token.attrs.some(attr => attr[0] === 'id' && attr[1].startsWith('ref:'));
248
+ }
249
+
250
+ function isHtmlRef(token) {
251
+ if (token.type !== 'html_block' && token.type !== 'html_inline') return false;
252
+ return token.content && token.content.includes('id="ref:');
253
+ }
254
+
255
+ function isInlineRef(token) {
256
+ if (token.type !== 'inline') return false;
257
+ return token.content && token.content.includes('id="ref:');
252
258
  }
253
259
 
254
260
  /**
@@ -256,6 +262,10 @@ module.exports = function (md, templates = {}) {
256
262
  * Handles special styling for terminology sections and processes definition terms and descriptions
257
263
  * This function was refactored to reduce cognitive complexity by extracting helper functions
258
264
  *
265
+ * IMPORTANT FIX: This function now checks if a <dl> already has a class attribute OR contains
266
+ * spec references (dt elements with id="ref:...") before adding the 'terms-and-definitions-list'
267
+ * class. This prevents spec reference lists from being incorrectly classified as term definition lists.
268
+ *
259
269
  * @param {Array} tokens - The token array being processed
260
270
  * @param {Number} idx - The index of the current token
261
271
  * @param {Object} options - Rendering options
@@ -267,8 +277,19 @@ module.exports = function (md, templates = {}) {
267
277
  const targetHtml = 'terminology-section-start';
268
278
  let targetIndex = findTargetIndex(tokens, targetHtml);
269
279
 
270
- // Add class to the first <dl> only if it comes after the target HTML
271
- if (targetIndex !== -1 && idx > targetIndex && !classAdded) {
280
+ // Check if the dl already has a class attribute (e.g., reference-list)
281
+ const existingClassIndex = tokens[idx].attrIndex('class');
282
+ const hasExistingClass = existingClassIndex >= 0;
283
+
284
+ // Check if this dl contains spec references (dt elements with id="ref:...")
285
+ const hasSpecReferences = containsSpecReferences(tokens, idx + 1);
286
+
287
+ // Only add terms-and-definitions-list class if:
288
+ // 1. It comes after the target HTML
289
+ // 2. We haven't added the class yet
290
+ // 3. The dl doesn't already have a class (to avoid overriding reference-list)
291
+ // 4. The dl doesn't contain spec references
292
+ if (targetIndex !== -1 && idx > targetIndex && !classAdded && !hasExistingClass && !hasSpecReferences) {
272
293
  tokens[idx].attrPush(['class', 'terms-and-definitions-list']);
273
294
  classAdded = true;
274
295
  }