spec-up-t 1.3.0 → 1.4.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 (150) hide show
  1. package/.github/copilot-instructions.md +13 -0
  2. package/assets/compiled/body.js +18 -12
  3. package/assets/compiled/head.css +8 -6
  4. package/assets/css/collapse-definitions.css +0 -1
  5. package/assets/css/counter.css +10 -22
  6. package/assets/css/create-pdf.css +4 -2
  7. package/assets/css/create-term-filter.css +4 -4
  8. package/assets/css/definition-buttons-container.css +60 -0
  9. package/assets/css/{pdf-download.css → download-pdf-docx.css} +9 -5
  10. package/assets/css/insert-trefs.css +7 -0
  11. package/assets/css/sidebar-toc.css +2 -1
  12. package/assets/css/terms-and-definitions.css +73 -22
  13. package/assets/js/add-href-to-snapshot-link.js +16 -9
  14. package/assets/js/addAnchorsToTerms.js +2 -2
  15. package/assets/js/charts.js +10 -0
  16. package/assets/js/collapse-definitions.js +13 -2
  17. package/assets/js/collapse-meta-info.js +11 -9
  18. package/assets/js/definition-button-container-utils.js +82 -0
  19. package/assets/js/download-pdf-docx.js +68 -0
  20. package/assets/js/edit-term-buttons.js +77 -20
  21. package/assets/js/github-issues.js +35 -0
  22. package/assets/js/github-repo-info.js +144 -0
  23. package/assets/js/highlight-heading-plus-sibling-nodes.test.js +18 -0
  24. package/assets/js/insert-trefs.js +62 -13
  25. package/assets/js/mermaid-diagrams.js +11 -0
  26. package/assets/js/terminology-section-utility-container/README.md +107 -0
  27. package/assets/js/terminology-section-utility-container/create-alphabet-index.js +17 -0
  28. package/assets/js/{create-term-filter.js → terminology-section-utility-container/create-term-filter.js} +11 -44
  29. package/assets/js/terminology-section-utility-container/hide-show-utility-container.js +21 -0
  30. package/assets/js/terminology-section-utility-container/search.js +203 -0
  31. package/assets/js/terminology-section-utility-container.js +203 -0
  32. package/assets/js/tooltips.js +283 -0
  33. package/config/asset-map.json +26 -18
  34. package/index.js +57 -390
  35. package/package.json +5 -2
  36. package/src/add-remove-xref-source.js +20 -21
  37. package/src/collect-external-references.js +8 -337
  38. package/src/collect-external-references.test.js +440 -33
  39. package/src/configure.js +8 -109
  40. package/src/create-docx.js +7 -6
  41. package/src/create-pdf.js +15 -14
  42. package/src/freeze-spec-data.js +46 -0
  43. package/src/git-info.test.js +76 -0
  44. package/src/health-check/destination-gitignore-checker.js +5 -3
  45. package/src/health-check/external-specs-checker.js +5 -4
  46. package/src/health-check/specs-configuration-checker.js +2 -1
  47. package/src/health-check/term-references-checker.js +5 -3
  48. package/src/health-check/terms-intro-checker.js +2 -1
  49. package/src/health-check/tref-term-checker.js +8 -7
  50. package/src/health-check.js +8 -7
  51. package/src/init.js +3 -2
  52. package/src/install-from-boilerplate/add-gitignore-entries.js +3 -2
  53. package/src/install-from-boilerplate/add-scripts-keys.js +5 -4
  54. package/src/install-from-boilerplate/boilerplate/.github/workflows/menu.yml +74 -97
  55. package/src/install-from-boilerplate/boilerplate/README.md +1 -1
  56. package/src/install-from-boilerplate/boilerplate/spec/example-markup-in-markdown.md +1 -1
  57. package/src/install-from-boilerplate/boilerplate/spec/spec-head.md +2 -2
  58. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/composability.md +3 -0
  59. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/compost.md +3 -0
  60. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/fertilizer.md +3 -0
  61. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/mulch.md +3 -0
  62. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/pruning.md +3 -0
  63. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/seedling.md +3 -0
  64. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/soil.md +11 -0
  65. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/watering.md +3 -0
  66. package/src/install-from-boilerplate/boilerplate/specs.json +24 -10
  67. package/src/install-from-boilerplate/config-scripts-keys.js +3 -3
  68. package/src/install-from-boilerplate/config-system-files.js +0 -1
  69. package/src/install-from-boilerplate/copy-boilerplate.js +2 -1
  70. package/src/install-from-boilerplate/copy-system-files.js +4 -3
  71. package/src/install-from-boilerplate/custom-update.js +12 -1
  72. package/src/install-from-boilerplate/help.txt +1 -1
  73. package/src/install-from-boilerplate/menu.sh +6 -6
  74. package/src/json-key-validator.js +17 -11
  75. package/src/markdown-it/README.md +207 -0
  76. package/src/markdown-it/definition-lists.js +397 -0
  77. package/src/markdown-it/index.js +83 -0
  78. package/src/markdown-it/link-enhancement.js +98 -0
  79. package/src/markdown-it/plugins.js +118 -0
  80. package/src/markdown-it/table-enhancement.js +97 -0
  81. package/src/markdown-it/template-tag-syntax.js +152 -0
  82. package/src/parsers/index.js +16 -0
  83. package/src/parsers/spec-parser.js +152 -0
  84. package/src/parsers/spec-parser.test.js +109 -0
  85. package/src/parsers/template-tag-parser.js +277 -0
  86. package/src/parsers/template-tag-parser.test.js +107 -0
  87. package/src/pipeline/configuration/configure-starterpack.js +200 -0
  88. package/src/{create-external-specs-list.js → pipeline/configuration/create-external-specs-list.js} +13 -12
  89. package/src/{create-term-index.js → pipeline/configuration/create-term-index.js} +19 -18
  90. package/src/{create-versions-index.js → pipeline/configuration/create-versions-index.js} +4 -3
  91. package/src/{insert-term-index.js → pipeline/configuration/insert-term-index.js} +2 -2
  92. package/src/pipeline/configuration/prepare-spec-configuration.js +70 -0
  93. package/src/pipeline/parsing/apply-markdown-it-extensions.js +35 -0
  94. package/src/pipeline/parsing/create-markdown-parser.js +94 -0
  95. package/src/pipeline/parsing/create-markdown-parser.test.js +49 -0
  96. package/src/{html-dom-processor.js → pipeline/postprocessing/definition-list-postprocessor.js} +69 -10
  97. package/src/{escape-handler.js → pipeline/preprocessing/escape-processor.js} +3 -1
  98. package/src/{fix-markdown-files.js → pipeline/preprocessing/normalize-terminology-markdown.js} +41 -31
  99. package/src/pipeline/references/collect-external-references.js +307 -0
  100. package/src/pipeline/references/external-references-service.js +231 -0
  101. package/src/pipeline/references/fetch-terms-from-index.js +198 -0
  102. package/src/pipeline/references/match-term.js +34 -0
  103. package/src/{collectExternalReferences/matchTerm.test.js → pipeline/references/match-term.test.js} +8 -2
  104. package/src/pipeline/references/process-xtrefs-data.js +94 -0
  105. package/src/pipeline/references/xtref-utils.js +166 -0
  106. package/src/pipeline/rendering/render-spec-document.js +146 -0
  107. package/src/pipeline/rendering/render-utils.js +154 -0
  108. package/src/utils/LOGGER.md +81 -0
  109. package/src/utils/{doesUrlExist.js → does-url-exist.js} +4 -3
  110. package/src/utils/fetch.js +5 -4
  111. package/src/utils/file-opener.js +3 -2
  112. package/src/utils/git-info.js +77 -0
  113. package/src/utils/logger.js +74 -0
  114. package/src/utils/regex-patterns.js +471 -0
  115. package/src/utils/regex-patterns.test.js +281 -0
  116. package/templates/template.html +56 -21
  117. package/assets/js/create-alphabet-index.js +0 -60
  118. package/assets/js/hide-show-utility-container.js +0 -16
  119. package/assets/js/index.js +0 -87
  120. package/assets/js/pdf-download.js +0 -46
  121. package/assets/js/search.js +0 -365
  122. package/src/collectExternalReferences/fetchTermsFromIndex.js +0 -284
  123. package/src/collectExternalReferences/matchTerm.js +0 -32
  124. package/src/collectExternalReferences/processXTrefsData.js +0 -108
  125. package/src/freeze.js +0 -90
  126. package/src/install-from-boilerplate/boilerplate/.github/workflows/fetch-and-push-xrefs.yml.old +0 -42
  127. package/src/install-from-boilerplate/boilerplate/.github/workflows/render-specs.yml +0 -47
  128. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-1.md +0 -13
  129. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-2.md +0 -3
  130. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-3.md +0 -3
  131. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-4.md +0 -3
  132. package/src/markdown-it-extensions.js +0 -395
  133. package/src/references.js +0 -114
  134. /package/assets/css/{bootstrap.min.css → embedded-libraries/bootstrap.min.css} +0 -0
  135. /package/assets/css/{prism.css → embedded-libraries/prism.css} +0 -0
  136. /package/assets/css/{prism.dark.css → embedded-libraries/prism.dark.css} +0 -0
  137. /package/assets/css/{prism.default.css → embedded-libraries/prism.default.css} +0 -0
  138. /package/assets/js/{bootstrap.bundle.min.js → embedded-libraries/bootstrap.bundle.min.js} +0 -0
  139. /package/assets/js/{chart.js → embedded-libraries/chart.js} +0 -0
  140. /package/assets/js/{diff.min.js → embedded-libraries/diff.min.js} +0 -0
  141. /package/assets/js/{font-awesome.js → embedded-libraries/font-awesome.js} +0 -0
  142. /package/assets/js/{mermaid.js → embedded-libraries/mermaid.js} +0 -0
  143. /package/assets/js/{notyf.js → embedded-libraries/notyf.js} +0 -0
  144. /package/assets/js/{popper.js → embedded-libraries/popper.js} +0 -0
  145. /package/assets/js/{prism.dark.js → embedded-libraries/prism.dark.js} +0 -0
  146. /package/assets/js/{prism.default.js → embedded-libraries/prism.default.js} +0 -0
  147. /package/assets/js/{prism.js → embedded-libraries/prism.js} +0 -0
  148. /package/assets/js/{tippy.js → embedded-libraries/tippy.js} +0 -0
  149. /package/src/{escape-mechanism.js → pipeline/preprocessing/escape-placeholder-utils.js} +0 -0
  150. /package/src/utils/{isLineWithDefinition.js → is-line-with-definition.js} +0 -0
@@ -1,395 +0,0 @@
1
- 'use strict';
2
-
3
- const { ESCAPED_PLACEHOLDER } = require('./escape-handler');
4
-
5
- /**
6
- * Configuration for custom template syntax [[example]] used throughout the markdown parsing
7
- * These constants define how template markers are identified and processed
8
- */
9
- const levels = 2; // Number of bracket characters used for template markers
10
- const openString = '['.repeat(levels); // Opening delimiter for template markers, e.g., '[['
11
- const closeString = ']'.repeat(levels); // Closing delimiter for template markers, e.g., ']]'
12
- // Regular expression to extract template type and arguments from content between delimiters
13
- // Captures: 1st group = template type (e.g., "ref", "tref"), 2nd group = optional arguments
14
- const contentRegex = /\s*([^\s\[\]:]+):?\s*([^\]\n]+)?/i;
15
-
16
- module.exports = function (md, templates = {}) {
17
-
18
- // Add table renderer to apply Bootstrap classes to all tables by default
19
- const originalTableRender = md.renderer.rules.table_open || function (tokens, idx, options, env, self) {
20
- return self.renderToken(tokens, idx, options);
21
- };
22
-
23
- // Save the original table_close renderer
24
- const originalTableCloseRender = md.renderer.rules.table_close || function (tokens, idx, options, env, self) {
25
- return self.renderToken(tokens, idx, options);
26
- };
27
-
28
- // Override table_open to add both the classes and open a wrapper div
29
- md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
30
- // Add Bootstrap classes to the table element
31
- const token = tokens[idx];
32
- const classIndex = token.attrIndex('class');
33
- const tableClasses = 'table table-striped table-bordered table-hover';
34
-
35
- if (classIndex < 0) {
36
- token.attrPush(['class', tableClasses]);
37
- } else {
38
- // If a class attribute already exists, append our classes
39
- const existingClasses = token.attrs[classIndex][1];
40
- // Only add classes that aren't already present
41
- const classesToAdd = tableClasses
42
- .split(' ')
43
- .filter(cls => !existingClasses.includes(cls))
44
- .join(' ');
45
-
46
- if (classesToAdd) {
47
- token.attrs[classIndex][1] = existingClasses + ' ' + classesToAdd;
48
- }
49
- }
50
-
51
- // Add the responsive wrapper div before the table
52
- return '<div class="table-responsive-md">' + originalTableRender(tokens, idx, options, env, self);
53
- };
54
-
55
- // Override table_close to close the wrapper div
56
- md.renderer.rules.table_close = function (tokens, idx, options, env, self) {
57
- // Close the table and add the closing div
58
- return originalTableCloseRender(tokens, idx, options, env, self) + '</div>';
59
- };
60
-
61
- /**
62
- * Custom template syntax rule for markdown-it
63
- * Processes template markers like [[template-type:arg1,arg2]] in markdown content
64
- * and converts them to tokens that can be processed by template renderers
65
- */
66
- md.inline.ruler.after('emphasis', 'templates', function templates_ruler(state, silent) {
67
- // Get the current parsing position
68
- var start = state.pos;
69
-
70
- // Check if we're at an escaped placeholder - if so, skip processing
71
- if (state.src.slice(start, start + ESCAPED_PLACEHOLDER.length) === ESCAPED_PLACEHOLDER) {
72
- return false;
73
- }
74
-
75
- // Check if we're at a template opening marker
76
- let prefix = state.src.slice(start, start + levels);
77
- if (prefix !== openString) return false;
78
- // Find the matching closing marker
79
- var indexOfClosingBrace = state.src.indexOf(closeString, start);
80
-
81
- if (indexOfClosingBrace > 0) {
82
- // Extract the template content using regex
83
- let match = contentRegex.exec(state.src.slice(start + levels, indexOfClosingBrace));
84
- if (!match) return false;
85
-
86
- // Get template type and find a matching template handler
87
- let type = match[1];
88
- let template = templates.find(t => t.filter(type) && t);
89
- if (!template) return false;
90
-
91
- // Parse template arguments (comma-separated)
92
- let args = match[2] ? match[2].trim().split(/\s*,+\s*/) : [];
93
- // Create a template token to be processed during rendering
94
- let token = state.push('template', '', 0);
95
- token.content = match[0];
96
- token.info = { type, template, args };
97
-
98
- // If the template has a parse function, use it to preprocess the token
99
- if (template.parse) {
100
- token.content = template.parse(token, type, ...args) || token.content;
101
- }
102
-
103
- // Advance the parser position past the template
104
- state.pos = indexOfClosingBrace + levels;
105
- return true;
106
- }
107
-
108
- return false;
109
- });
110
-
111
- /**
112
- * Renderer for template tokens
113
- * Takes template tokens created during parsing and renders them using their associated template handler
114
- */
115
- md.renderer.rules.template = function (tokens, idx, options, env, renderer) {
116
- let token = tokens[idx];
117
- let template = token.info.template;
118
- if (template.render) {
119
- return template.render(token, token.info.type, ...token.info.args) || (openString + token.content + closeString);
120
- }
121
- return token.content;
122
- }
123
-
124
- /**
125
- * Regular expression to extract domains and path segments from URLs
126
- * Used to add path-related attributes to links for styling and behavior
127
- */
128
- let pathSegmentRegex = /(?:http[s]*:\/\/([^\/]*)|(?:\/([^\/?]*)))/g;
129
-
130
- /**
131
- * Custom link_open renderer that adds path attributes for styling and behavior
132
- * Extracts domain and path segments from href attributes and adds them as path-X attributes
133
- */
134
- md.renderer.rules.link_open = function (tokens, idx, options, env, renderer) {
135
- let token = tokens[idx];
136
- let attrs = token.attrs.reduce((str, attr) => {
137
- let name = attr[0];
138
- let value = attr[1];
139
- if (name === 'href') {
140
- let index = 0;
141
- value.replace(pathSegmentRegex, (m, domain, seg) => {
142
- str += `path-${index++}="${domain || seg}"`;
143
- });
144
- }
145
- return str += name + '="' + value + '" ';
146
- }, '');
147
- let anchor = `<a ${attrs}>`;
148
- // Special handling for auto-detected links (linkify)
149
- return token.markup === 'linkify' ? anchor + '<span>' : anchor;
150
- }
151
-
152
- md.renderer.rules.link_close = function (tokens, idx, options, env, renderer) {
153
- return tokens[idx].markup === 'linkify' ? '</span></a>' : '</a>';
154
- }
155
-
156
- // Add class to <dl> and the last <dd> in each series after a <dt>
157
- const originalRender = md.renderer.rules.dl_open || function (tokens, idx, options, env, self) {
158
- return self.renderToken(tokens, idx, options);
159
- };
160
-
161
- // Variable to keep track of whether the class has been added to the first <dl> after the target HTML
162
- let classAdded = false;
163
-
164
- /**
165
- * Helper function to locate a specific marker in the token stream
166
- * Used to identify the terminology section in the document
167
- *
168
- * @param {Array} tokens - The token array to search through
169
- * @param {String} targetHtml - The HTML string to look for in token content
170
- * @return {Number} The index of the token containing targetHtml, or -1 if not found
171
- */
172
- function findTargetIndex(tokens, targetHtml) {
173
- for (let i = 0; i < tokens.length; i++) {
174
- if (tokens[i].content && tokens[i].content.includes(targetHtml)) {
175
- return i;
176
- }
177
- }
178
- return -1;
179
- }
180
-
181
- /**
182
- * Helper function to identify and mark empty definition term elements
183
- * Empty dt elements cause rendering and styling issues, so we mark them for special handling
184
- *
185
- * @param {Array} tokens - The token array to process
186
- * @param {Number} startIdx - The index in the token array to start processing from
187
- */
188
- function markEmptyDtElements(tokens, startIdx) {
189
- for (let i = startIdx; i < tokens.length; i++) {
190
- if (tokens[i].type === 'dl_close') {
191
- break; // Stop when we reach the end of this definition list
192
- }
193
-
194
- // An empty dt element is one where dt_open is immediately followed by dt_close
195
- // with no content in between
196
- if (tokens[i].type === 'dt_open' &&
197
- i + 1 < tokens.length &&
198
- tokens[i + 1].type === 'dt_close') {
199
- // Mark both opening and closing tokens so they can be skipped during rendering
200
- tokens[i].isEmpty = true;
201
- tokens[i + 1].isEmpty = true;
202
- }
203
- }
204
- }
205
-
206
-
207
- /**
208
- * Helper function to process definition description elements
209
- * Identifies and marks the last dd element in each dt/dd group for special styling
210
- *
211
- * @param {Array} tokens - The token array to process
212
- * @param {Number} startIdx - The index in the token array to start processing from
213
- */
214
- function processLastDdElements(tokens, startIdx) {
215
- let lastDdIndex = -1; // Tracks the most recent dd_open token
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) {
228
- for (let i = startIdx; i < tokens.length; i++) {
229
- if (tokens[i].type === 'dl_close') {
230
- break; // Stop when we reach the end of this definition list
231
- }
232
- if (isDtRef(tokens[i])) {
233
- return true;
234
- }
235
- if (isHtmlRef(tokens[i])) {
236
- return true;
237
- }
238
- if (isInlineRef(tokens[i])) {
239
- return true;
240
- }
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:');
258
- }
259
-
260
- /**
261
- * Custom renderer for definition list opening tags
262
- * Handles special styling for terminology sections and processes definition terms and descriptions
263
- * This function was refactored to reduce cognitive complexity by extracting helper functions
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
- *
269
- * @param {Array} tokens - The token array being processed
270
- * @param {Number} idx - The index of the current token
271
- * @param {Object} options - Rendering options
272
- * @param {Object} env - Environment variables
273
- * @param {Object} self - Reference to the renderer
274
- * @return {String} The rendered HTML output
275
- */
276
- md.renderer.rules.dl_open = function (tokens, idx, options, env, self) {
277
- const targetHtml = 'terminology-section-start';
278
- let targetIndex = findTargetIndex(tokens, targetHtml);
279
-
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) {
293
- tokens[idx].attrPush(['class', 'terms-and-definitions-list']);
294
- classAdded = true;
295
- }
296
-
297
- // First pass - mark empty dt elements
298
- markEmptyDtElements(tokens, idx + 1);
299
-
300
- // Second pass - process last dd elements
301
- processLastDdElements(tokens, idx + 1);
302
-
303
- return originalRender(tokens, idx, options, env, self);
304
- };
305
-
306
- /**
307
- * Helper function to determine if a definition term is transcluded from another source
308
- * Transcluded terms require special styling and handling
309
- *
310
- * @param {Array} tokens - The token array to process
311
- * @param {Number} dtOpenIndex - The index of the dt_open token to check
312
- * @return {Boolean} True if the term is transcluded, false otherwise
313
- */
314
- function isTermTranscluded(tokens, dtOpenIndex) {
315
- for (let i = dtOpenIndex + 1; i < tokens.length; i++) {
316
- if (tokens[i].type === 'dt_close') {
317
- break; // Only examine tokens within this definition term
318
- }
319
-
320
- // Look for inline content that contains template tokens of type 'tref'
321
- // These are transcluded term references
322
- if (tokens[i].type === 'inline' && tokens[i].children) {
323
- for (let child of tokens[i].children) {
324
- if (child.type === 'template' &&
325
- child.info &&
326
- child.info.type === 'tref') {
327
- return true;
328
- }
329
- }
330
- }
331
- }
332
- return false;
333
- }
334
-
335
- // Override the rendering of dt elements to properly handle transcluded terms
336
- const originalDtRender = md.renderer.rules.dt_open || function (tokens, idx, options, env, self) {
337
- return self.renderToken(tokens, idx, options);
338
- };
339
-
340
- /**
341
- * Custom renderer for definition term opening tags
342
- * Handles special cases like empty terms and transcluded terms
343
- *
344
- * @param {Array} tokens - The token array being processed
345
- * @param {Number} idx - The index of the current token
346
- * @param {Object} options - Rendering options
347
- * @param {Object} env - Environment variables
348
- * @param {Object} self - Reference to the renderer
349
- * @return {String} The rendered HTML output or empty string for skipped elements
350
- */
351
- md.renderer.rules.dt_open = function (tokens, idx, options, env, self) {
352
- // Skip rendering empty dt elements that were marked during preprocessing
353
- if (tokens[idx].isEmpty) {
354
- return '';
355
- }
356
-
357
- // Check if this dt is part of a transcluded term and add appropriate class
358
- if (isTermTranscluded(tokens, idx)) {
359
- const classIndex = tokens[idx].attrIndex('class');
360
- if (classIndex < 0) {
361
- tokens[idx].attrPush(['class', 'transcluded-xref-term']);
362
- } else {
363
- tokens[idx].attrs[classIndex][1] += ' transcluded-xref-term';
364
- }
365
- }
366
-
367
- return originalDtRender(tokens, idx, options, env, self);
368
- };
369
-
370
- // Similarly override dt_close to skip empty dts
371
- const originalDtCloseRender = md.renderer.rules.dt_close || function (tokens, idx, options, env, self) {
372
- return self.renderToken(tokens, idx, options);
373
- };
374
-
375
- /**
376
- * Custom renderer for definition term closing tags
377
- * Ensures empty terms are not rendered in the final output
378
- *
379
- * @param {Array} tokens - The token array being processed
380
- * @param {Number} idx - The index of the current token
381
- * @param {Object} options - Rendering options
382
- * @param {Object} env - Environment variables
383
- * @param {Object} self - Reference to the renderer
384
- * @return {String} The rendered HTML output or empty string for skipped elements
385
- */
386
- md.renderer.rules.dt_close = function (tokens, idx, options, env, self) {
387
- // Skip rendering the closing </dt> tag for empty dt elements
388
- // This completes the fix for empty dt elements by ensuring neither
389
- // the opening nor closing tags are rendered
390
- if (tokens[idx].isEmpty) {
391
- return '';
392
- }
393
- return originalDtCloseRender(tokens, idx, options, env, self);
394
- };
395
- };
package/src/references.js DELETED
@@ -1,114 +0,0 @@
1
- const {JSDOM} = require("jsdom");
2
- const axios = require('axios').default;
3
-
4
- const spaceRegex = /\s+/g;
5
-
6
- function validateReferences(references, definitions, render) {
7
- const unresolvedRefs = [];
8
- [...new Set(references)].forEach(
9
- ref => {
10
- if(render.includes(`id="term:${ref.replace(spaceRegex, '-').toLowerCase()}"`)) {
11
- // Reference is resolved
12
- } else {
13
- unresolvedRefs.push(ref);
14
- }
15
- }
16
- );
17
- if (unresolvedRefs.length > 0 ) {
18
- console.log('ℹ️ Unresolved References: ', unresolvedRefs)
19
- }
20
-
21
- const danglingDefs = [];
22
- definitions.forEach(defs => {
23
- let found = defs.some(def => render.includes(`href="#term:${def.replace(spaceRegex, '-').toLowerCase()}"`))
24
- if (!found) {
25
- danglingDefs.push(defs[0]);
26
- }
27
- })
28
- if(danglingDefs.length > 0) {
29
- console.log('ℹ️ Dangling Definitions: ', danglingDefs)
30
- }
31
- }
32
-
33
- function findExternalSpecByKey(config, key) {
34
- for (const spec of config.specs) {
35
- if (spec.external_specs) {
36
- for (const externalSpec of spec.external_specs) {
37
- if (externalSpec.external_spec === key) {
38
- return externalSpec;
39
- }
40
- }
41
- }
42
- }
43
- return null;
44
- }
45
-
46
- async function fetchExternalSpecs(spec) {
47
- try {
48
- let results = await Promise.all(
49
- spec.external_specs.map(s => {
50
- const url = s["gh_page"];
51
- return axios.get(url).catch(error => ({ error, url }));
52
- })
53
- );
54
-
55
- const failed = results.filter(r => r && r.error);
56
- if (failed.length > 0) {
57
- failed.forEach(f => {
58
- const msg = f.error.response
59
- ? `HTTP ${f.error.response.status} for ${f.url}`
60
- : `Network error for ${f.url}: ${f.error.message}`;
61
- console.error("❌ External spec fetch failed:", msg);
62
- });
63
- }
64
-
65
- // Map results to objects keyed by external_spec if status is 200, otherwise null.
66
- // This ensures only successful fetches are included, and failed ones are filtered out.
67
- results = results
68
- .map((r, index) =>
69
- r && r.status === 200
70
- ? { [spec.external_specs[index].external_spec]: r.data }
71
- : null
72
- )
73
- .filter(r => r); // Remove null values (failed fetches)
74
-
75
- return results.map(r =>
76
- createNewDLWithTerms(Object.keys(r)[0], Object.values(r)[0])
77
- );
78
- } catch (e) {
79
- console.error("❌ Unexpected error in fetchExternalSpecs:", e);
80
- return [];
81
- }
82
- }
83
-
84
-
85
- function createNewDLWithTerms(title, html) {
86
- const dom = new JSDOM(html);
87
- const document = dom.window.document;
88
-
89
- const newDl = document.createElement('dl');
90
- newDl.setAttribute('id', title);
91
-
92
- const terms = document.querySelectorAll('dt span[id^="term:"]');
93
-
94
- terms.forEach(term => {
95
- const modifiedId = `term:${title}:${term.id.split(':')[1]}`;
96
- term.id = modifiedId;
97
- const dt = term.closest('dt');
98
- const dd = dt.nextElementSibling;
99
-
100
- newDl.appendChild(dt.cloneNode(true));
101
- if (dd && dd.tagName === 'DD') {
102
- newDl.appendChild(dd.cloneNode(true));
103
- }
104
- });
105
-
106
- return newDl.outerHTML;
107
- }
108
-
109
- module.exports = {
110
- findExternalSpecByKey,
111
- validateReferences,
112
- fetchExternalSpecs,
113
- createNewDLWithTerms
114
- }