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,5 +1,17 @@
1
+ const {
2
+ collectExternalReferences,
3
+ extendXTrefs,
4
+ processExternalReferences
5
+ } = require('./pipeline/references/collect-external-references');
6
+ const {
7
+ isXTrefInMarkdown,
8
+ isXTrefInAnyFile,
9
+ addNewXTrefsFromMarkdown
10
+ } = require('./pipeline/references/xtref-utils');
11
+ const { processXTrefObject } = require('./parsers/template-tag-parser');
12
+
13
+ // Tests for detecting and matching external references in markdown content
1
14
  describe('isXTrefInMarkdown function', () => {
2
- const isXTrefInMarkdown = require('./collect-external-references').isXTrefInMarkdown;
3
15
 
4
16
  const testCases = [
5
17
  {
@@ -144,25 +156,28 @@ That's all about these references.`,
144
156
  });
145
157
 
146
158
 
159
+ // Tests for extracting and collecting external references from markdown
147
160
  describe('addNewXTrefsFromMarkdown', () => {
148
- const addNewXTrefsFromMarkdown = require('./collect-external-references').addNewXTrefsFromMarkdown;
149
161
 
162
+ // Test: Can the system extract basic references from markdown?
150
163
  it('should add a new xtref from markdown content', () => {
151
164
  const markdownContent = "Some text [[xref:specA, termA]] more text";
152
165
  const allXTrefs = { xtrefs: [] };
153
- const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
166
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
154
167
 
155
168
  expect(updatedXTrefs.xtrefs.length).toBe(1);
156
169
  expect(updatedXTrefs.xtrefs[0]).toEqual({
157
170
  externalSpec: 'specA',
158
- term: 'termA'
171
+ term: 'termA',
172
+ trefAliases: [],
173
+ xrefAliases: []
159
174
  });
160
175
  });
161
176
 
162
177
  it('should not add duplicate xtrefs with same spec and term but different aliases', () => {
163
178
  const markdownContent = "Content [[xref:specA, termA]] and again [[xref:specA, termA, aliasA]]";
164
179
  const allXTrefs = { xtrefs: [] };
165
- const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
180
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
166
181
 
167
182
  expect(updatedXTrefs.xtrefs.length).toBe(1);
168
183
  expect(updatedXTrefs.xtrefs[0].term).toBe('termA');
@@ -173,21 +188,33 @@ describe('addNewXTrefsFromMarkdown', () => {
173
188
  it('should add multiple distinct xtrefs', () => {
174
189
  const markdownContent = "[[xref:specA, termA]] some text [[tref:specB, termB]]";
175
190
  const allXTrefs = { xtrefs: [] };
176
- const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
191
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
177
192
 
178
193
  expect(updatedXTrefs.xtrefs.length).toBe(2);
179
194
  expect(updatedXTrefs.xtrefs).toEqual(
180
195
  expect.arrayContaining([
181
- { externalSpec: 'specA', term: 'termA' },
182
- { externalSpec: 'specB', term: 'termB' }
196
+ { externalSpec: 'specA', term: 'termA', trefAliases: [], xrefAliases: [] },
197
+ { externalSpec: 'specB', term: 'termB', trefAliases: [], xrefAliases: [] }
183
198
  ])
184
199
  );
185
200
  });
186
201
 
202
+ it('should not add duplicate xtrefs with same spec and term but different aliases', () => {
203
+ const markdownContent = "Content [[xref:specA, termA]] and again [[xref:specA, termA, aliasA]]";
204
+ const allXTrefs = { xtrefs: [] };
205
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
206
+
207
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
208
+ expect(updatedXTrefs.xtrefs[0].term).toBe('termA');
209
+ expect(updatedXTrefs.xtrefs[0].externalSpec).toBe('specA');
210
+ expect(updatedXTrefs.xtrefs[0].externalSpec).toBe('specA');
211
+ // The first one found will be used (without alias in this case)
212
+ });
213
+
187
214
  it('should not change xtrefs when no xtrefs are found in markdown content', () => {
188
215
  const markdownContent = "This is markdown without any reference links.";
189
216
  const initialXTrefs = { xtrefs: [] };
190
- const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, initialXTrefs);
217
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, initialXTrefs, null, processXTrefObject);
191
218
 
192
219
  expect(updatedXTrefs.xtrefs.length).toBe(0);
193
220
  });
@@ -195,109 +222,489 @@ describe('addNewXTrefsFromMarkdown', () => {
195
222
  it('should add a new tref with alias from markdown content', () => {
196
223
  const markdownContent = "Some text [[tref:specA, termA, aliasA]] more text";
197
224
  const allXTrefs = { xtrefs: [] };
198
- const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
225
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
199
226
 
200
227
  expect(updatedXTrefs.xtrefs.length).toBe(1);
201
228
  expect(updatedXTrefs.xtrefs[0]).toEqual({
202
229
  externalSpec: 'specA',
203
230
  term: 'termA',
204
- alias: 'aliasA'
231
+ trefAliases: ['aliasA'],
232
+ xrefAliases: [],
233
+ firstTrefAlias: 'aliasA'
205
234
  });
206
235
  });
207
236
 
208
237
  it('should add a new xref with alias from markdown content', () => {
209
238
  const markdownContent = "Some text [[xref:specA, termA, aliasA]] more text";
210
239
  const allXTrefs = { xtrefs: [] };
211
- const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
240
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
212
241
 
213
242
  expect(updatedXTrefs.xtrefs.length).toBe(1);
214
243
  expect(updatedXTrefs.xtrefs[0]).toEqual({
215
244
  externalSpec: 'specA',
216
245
  term: 'termA',
217
- alias: 'aliasA'
246
+ trefAliases: [],
247
+ xrefAliases: ['aliasA'],
248
+ firstXrefAlias: 'aliasA'
218
249
  });
219
250
  });
220
251
 
221
252
  it('should handle tref without alias (backwards compatibility)', () => {
222
253
  const markdownContent = "Some text [[tref:specA, termA]] more text";
223
254
  const allXTrefs = { xtrefs: [] };
224
- const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
255
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
225
256
 
226
257
  expect(updatedXTrefs.xtrefs.length).toBe(1);
227
258
  expect(updatedXTrefs.xtrefs[0]).toEqual({
228
259
  externalSpec: 'specA',
229
- term: 'termA'
260
+ term: 'termA',
261
+ trefAliases: [], xrefAliases: []
230
262
  });
231
- expect(updatedXTrefs.xtrefs[0].alias).toBeUndefined();
232
263
  });
233
264
 
234
265
  });
235
266
 
236
267
 
237
- describe('processXTref', () => {
238
- const processXTref = require('./collect-external-references').processXTref;
268
+ // Tests for parsing individual external reference objects
269
+ describe('processXTrefObject', () => {
239
270
 
271
+ // Test: Can the system parse basic xref references?
240
272
  it('should process basic xref without alias', () => {
241
273
  const xtref = '[[xref:specA,termA]]';
242
- const result = processXTref(xtref);
274
+ const result = processXTrefObject(xtref);
243
275
 
244
276
  expect(result).toEqual({
245
277
  externalSpec: 'specA',
246
- term: 'termA'
278
+ term: 'termA',
279
+ referenceType: 'xref',
280
+ trefAliases: [],
281
+ xrefAliases: []
247
282
  });
248
283
  });
249
284
 
250
285
  it('should process basic tref without alias', () => {
251
286
  const xtref = '[[tref:specA,termA]]';
252
- const result = processXTref(xtref);
287
+ const result = processXTrefObject(xtref);
253
288
 
254
289
  expect(result).toEqual({
255
290
  externalSpec: 'specA',
256
- term: 'termA'
291
+ term: 'termA',
292
+ referenceType: 'tref',
293
+ trefAliases: [], xrefAliases: []
257
294
  });
258
295
  });
259
296
 
260
- it('should process tref with alias', () => {
297
+ it('should process tref with single alias', () => {
261
298
  const xtref = '[[tref:specA,termA,aliasA]]';
262
- const result = processXTref(xtref);
299
+ const result = processXTrefObject(xtref);
263
300
 
264
301
  expect(result).toEqual({
265
302
  externalSpec: 'specA',
266
303
  term: 'termA',
267
- alias: 'aliasA'
304
+ trefAliases: ['aliasA'], xrefAliases: [],
305
+ firstTrefAlias: 'aliasA',
306
+ referenceType: 'tref'
268
307
  });
269
308
  });
270
309
 
271
- it('should process xref with alias', () => {
310
+ it('should process xref with single alias', () => {
272
311
  const xtref = '[[xref:specA,termA,aliasA]]';
273
- const result = processXTref(xtref);
312
+ const result = processXTrefObject(xtref);
274
313
 
275
314
  expect(result).toEqual({
276
315
  externalSpec: 'specA',
277
316
  term: 'termA',
278
- alias: 'aliasA'
317
+ trefAliases: [],
318
+ xrefAliases: ['aliasA'],
319
+ firstXrefAlias: 'aliasA',
320
+ referenceType: 'xref'
321
+ });
322
+ });
323
+
324
+ it('should process tref with multiple aliases', () => {
325
+ const xtref = '[[tref:specA,termA,aliasA,aliasB]]';
326
+ const result = processXTrefObject(xtref);
327
+
328
+ expect(result).toEqual({
329
+ externalSpec: 'specA',
330
+ term: 'termA',
331
+ trefAliases: ['aliasA', 'aliasB'], xrefAliases: [],
332
+ firstTrefAlias: 'aliasA',
333
+ referenceType: 'tref'
279
334
  });
280
335
  });
281
336
 
282
337
  it('should handle spaces in parameters', () => {
283
338
  const xtref = '[[tref: specA , termA , aliasA ]]';
284
- const result = processXTref(xtref);
339
+ const result = processXTrefObject(xtref);
285
340
 
286
341
  expect(result).toEqual({
287
342
  externalSpec: 'specA',
288
343
  term: 'termA',
289
- alias: 'aliasA'
344
+ trefAliases: ['aliasA'], xrefAliases: [],
345
+ firstTrefAlias: 'aliasA',
346
+ referenceType: 'tref'
290
347
  });
291
348
  });
292
349
 
293
350
  it('should ignore empty alias parameter', () => {
294
351
  const xtref = '[[tref:specA,termA,]]';
295
- const result = processXTref(xtref);
352
+ const result = processXTrefObject(xtref);
353
+
354
+ expect(result).toEqual({
355
+ externalSpec: 'specA',
356
+ term: 'termA',
357
+ referenceType: 'tref',
358
+ trefAliases: [], xrefAliases: []
359
+ });
360
+ });
361
+
362
+ it('should not include firstTrefAlias property when no aliases exist for tref', () => {
363
+ const xtref = '[[tref:specA,termA]]';
364
+ const result = processXTrefObject(xtref);
296
365
 
297
366
  expect(result).toEqual({
298
367
  externalSpec: 'specA',
299
- term: 'termA'
368
+ term: 'termA',
369
+ referenceType: 'tref',
370
+ trefAliases: [], xrefAliases: []
371
+ });
372
+ expect(result.firstTrefAlias).toBeUndefined();
373
+ });
374
+
375
+ it('should correctly identify the first alias among multiple aliases', () => {
376
+ const xtref = '[[tref:specA,termA,firstAlias,secondAlias,thirdAlias]]';
377
+ const result = processXTrefObject(xtref);
378
+
379
+ expect(result).toEqual({
380
+ externalSpec: 'specA',
381
+ term: 'termA',
382
+ trefAliases: ['firstAlias', 'secondAlias', 'thirdAlias'],
383
+ xrefAliases: [],
384
+ firstTrefAlias: 'firstAlias',
385
+ referenceType: 'tref'
386
+ });
387
+ expect(result.firstTrefAlias).toBe('firstAlias');
388
+ expect(result.trefAliases[0]).toBe('firstAlias');
389
+ });
390
+ });
391
+
392
+ // Tests for tracking which files contain which references
393
+ describe('addNewXTrefsFromMarkdown with filename tracking', () => {
394
+
395
+ // Test: Does the system track which file a reference came from?
396
+ it('should add sourceFiles property when filename is provided', () => {
397
+ const markdownContent = "Some text [[xref:specA, termA]] more text";
398
+ const allXTrefs = { xtrefs: [] };
399
+ const filename = 'test-file.md';
400
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, filename, processXTrefObject);
401
+
402
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
403
+ expect(updatedXTrefs.xtrefs[0]).toEqual({
404
+ externalSpec: 'specA',
405
+ term: 'termA',
406
+ trefAliases: [],
407
+ xrefAliases: [],
408
+ sourceFiles: [{ file: 'test-file.md', type: 'xref' }]
409
+ });
410
+ });
411
+
412
+ it('should not add sourceFiles property when filename is not provided', () => {
413
+ const markdownContent = "Some text [[xref:specA, termA]] more text";
414
+ const allXTrefs = { xtrefs: [] };
415
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, null, processXTrefObject);
416
+
417
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
418
+ expect(updatedXTrefs.xtrefs[0]).toEqual({
419
+ externalSpec: 'specA',
420
+ term: 'termA',
421
+ trefAliases: [], xrefAliases: []
422
+ });
423
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toBeUndefined();
424
+ });
425
+
426
+ it('should create sourceFiles array when same xtref found in multiple files', () => {
427
+ const markdownContent1 = "Some text [[xref:specA, termA]] more text";
428
+ const markdownContent2 = "Different text [[xref:specA, termA]] here";
429
+ const allXTrefs = { xtrefs: [] };
430
+
431
+ // Add from first file
432
+ addNewXTrefsFromMarkdown(markdownContent1, allXTrefs, 'file1.md', processXTrefObject);
433
+ // Add from second file - should create sourceFiles array
434
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent2, allXTrefs, 'file2.md', processXTrefObject);
435
+
436
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
437
+ expect(updatedXTrefs.xtrefs[0].externalSpec).toBe('specA');
438
+ expect(updatedXTrefs.xtrefs[0].term).toBe('termA');
439
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
440
+ {file: 'file1.md', type: 'xref'},
441
+ {file: 'file2.md', type: 'xref'}
442
+ ]);
443
+ expect(updatedXTrefs.xtrefs[0].sourceFile).toBeUndefined();
444
+ expect(updatedXTrefs.xtrefs[0].referenceType).toBeUndefined();
445
+ });
446
+
447
+ it('should not duplicate filenames in sourceFiles array', () => {
448
+ const markdownContent = "Some text [[xref:specA, termA]] and again [[xref:specA, termA]]";
449
+ const allXTrefs = { xtrefs: [] };
450
+
451
+ // Process same file twice
452
+ addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'file1.md', processXTrefObject);
453
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'file1.md', processXTrefObject);
454
+
455
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
456
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
457
+ {file: 'file1.md', type: 'xref'}
458
+ ]);
459
+ });
460
+
461
+ it('should add to existing sourceFiles array when finding duplicate reference', () => {
462
+ const allXTrefs = {
463
+ xtrefs: [
464
+ {
465
+ externalSpec: 'specA',
466
+ term: 'termA',
467
+ sourceFiles: [{file: 'existing-file.md', type: 'tref'}]
468
+ }
469
+ ]
470
+ };
471
+ const markdownContent = "Text [[xref:specA, termA]] here";
472
+
473
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'new-file.md', processXTrefObject);
474
+
475
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
476
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
477
+ {file: 'existing-file.md', type: 'tref'},
478
+ {file: 'new-file.md', type: 'xref'}
479
+ ]);
480
+ expect(updatedXTrefs.xtrefs[0].sourceFile).toBeUndefined();
481
+ expect(updatedXTrefs.xtrefs[0].referenceType).toBeUndefined();
482
+ });
483
+ });
484
+
485
+ // Tests for finding references across multiple files
486
+ describe('isXTrefInAnyFile', () => {
487
+
488
+ // Test: Can the system find references across multiple files?
489
+ it('should return true when xtref is found in at least one file', () => {
490
+ const xtref = { externalSpec: 'specA', term: 'termA' };
491
+ const fileContents = new Map([
492
+ ['file1.md', 'Some content without xrefs'],
493
+ ['file2.md', 'Content with [[xref:specA,termA]] reference'],
494
+ ['file3.md', 'More content without xrefs']
495
+ ]);
496
+
497
+ const result = isXTrefInAnyFile(xtref, fileContents);
498
+ expect(result).toBe(true);
499
+ });
500
+
501
+ it('should return false when xtref is not found in any file', () => {
502
+ const xtref = { externalSpec: 'specA', term: 'termA' };
503
+ const fileContents = new Map([
504
+ ['file1.md', 'Some content without xrefs'],
505
+ ['file2.md', 'Content with [[xref:specB,termB]] reference'],
506
+ ['file3.md', 'More content without xrefs']
507
+ ]);
508
+
509
+ const result = isXTrefInAnyFile(xtref, fileContents);
510
+ expect(result).toBe(false);
511
+ });
512
+
513
+ it('should handle empty file contents map', () => {
514
+ const xtref = { externalSpec: 'specA', term: 'termA' };
515
+ const fileContents = new Map();
516
+
517
+ const result = isXTrefInAnyFile(xtref, fileContents);
518
+ expect(result).toBe(false);
519
+ });
520
+ });
521
+
522
+ // Tests for tracking different reference types (xref vs tref)
523
+ describe('Reference type tracking', () => {
524
+
525
+ // Test: Does the system distinguish between xref and tref types?
526
+ it('should track xref reference type in sourceFiles when filename provided', () => {
527
+ const markdownContent = "Some text [[xref:specA, termA]] more text";
528
+ const allXTrefs = { xtrefs: [] };
529
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'test.md', processXTrefObject);
530
+
531
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
532
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
533
+ {file: 'test.md', type: 'xref'}
534
+ ]);
535
+ });
536
+
537
+ it('should track tref reference type in sourceFiles when filename provided', () => {
538
+ const markdownContent = "Some text [[tref:specA, termA]] more text";
539
+ const allXTrefs = { xtrefs: [] };
540
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'test.md', processXTrefObject);
541
+
542
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
543
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
544
+ {file: 'test.md', type: 'tref'}
545
+ ]);
546
+ });
547
+
548
+ it('should convert to sourceFiles array when same term found as both xref and tref in different files', () => {
549
+ const markdownContent1 = "Text with [[xref:specA, termA]] reference";
550
+ const markdownContent2 = "Text with [[tref:specA, termA]] reference";
551
+ const allXTrefs = { xtrefs: [] };
552
+
553
+ // Add xref first
554
+ addNewXTrefsFromMarkdown(markdownContent1, allXTrefs, 'file1.md', processXTrefObject);
555
+ expect(allXTrefs.xtrefs[0].sourceFiles).toEqual([
556
+ {file: 'file1.md', type: 'xref'}
557
+ ]);
558
+
559
+ // Add tref for same term in different file - should expand sourceFiles array
560
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent2, allXTrefs, 'file2.md', processXTrefObject);
561
+
562
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
563
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
564
+ {file: 'file1.md', type: 'xref'},
565
+ {file: 'file2.md', type: 'tref'}
566
+ ]);
567
+ expect(updatedXTrefs.xtrefs[0].referenceType).toBeUndefined();
568
+ expect(updatedXTrefs.xtrefs[0].sourceFile).toBeUndefined();
569
+ });
570
+
571
+ it('should not duplicate reference types in same file', () => {
572
+ const markdownContent = "Text [[xref:specA, termA]] and again [[xref:specA, termA]]";
573
+ const allXTrefs = { xtrefs: [] };
574
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'file1.md', processXTrefObject);
575
+
576
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
577
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
578
+ {file: 'file1.md', type: 'xref'}
579
+ ]);
580
+ });
581
+
582
+ it('should handle same term with different reference types in same file', () => {
583
+ const markdownContent = "Text [[xref:specA, termA]] and [[tref:specA, termA]]";
584
+ const allXTrefs = { xtrefs: [] };
585
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'file1.md', processXTrefObject);
586
+
587
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
588
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
589
+ {file: 'file1.md', type: 'xref'},
590
+ {file: 'file1.md', type: 'tref'}
591
+ ]);
592
+ expect(updatedXTrefs.xtrefs[0].referenceType).toBeUndefined();
593
+ expect(updatedXTrefs.xtrefs[0].sourceFile).toBeUndefined();
594
+ });
595
+
596
+ it('should add new file/type combination to existing sourceFiles array', () => {
597
+ const allXTrefs = {
598
+ xtrefs: [
599
+ {
600
+ externalSpec: 'specA',
601
+ term: 'termA',
602
+ sourceFiles: [
603
+ {file: 'file1.md', type: 'xref'}
604
+ ]
605
+ }
606
+ ]
607
+ };
608
+ const markdownContent = "Text with [[tref:specA, termA]] reference";
609
+
610
+ const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs, 'file2.md', processXTrefObject);
611
+
612
+ expect(updatedXTrefs.xtrefs.length).toBe(1);
613
+ expect(updatedXTrefs.xtrefs[0].sourceFiles).toEqual([
614
+ {file: 'file1.md', type: 'xref'},
615
+ {file: 'file2.md', type: 'tref'}
616
+ ]);
617
+ });
618
+
619
+ it('should handle complex scenario with both filename and reference type tracking', () => {
620
+ const allXTrefs = { xtrefs: [] };
621
+
622
+ // Add xref from file1
623
+ addNewXTrefsFromMarkdown("[[xref:specA, termA]]", allXTrefs, 'file1.md', processXTrefObject);
624
+ expect(allXTrefs.xtrefs[0]).toEqual({
625
+ externalSpec: 'specA',
626
+ term: 'termA',
627
+ trefAliases: [], xrefAliases: [],
628
+ sourceFiles: [{ file: 'file1.md', type: 'xref' }]
629
+ });
630
+
631
+ // Add tref from file2 - should convert to sourceFiles array with detailed tracking
632
+ addNewXTrefsFromMarkdown("[[tref:specA, termA]]", allXTrefs, 'file2.md', processXTrefObject);
633
+
634
+ expect(allXTrefs.xtrefs.length).toBe(1);
635
+ expect(allXTrefs.xtrefs[0]).toEqual({
636
+ externalSpec: 'specA',
637
+ term: 'termA',
638
+ trefAliases: [], xrefAliases: [],
639
+ sourceFiles: [
640
+ {file: 'file1.md', type: 'xref'},
641
+ {file: 'file2.md', type: 'tref'}
642
+ ]
643
+ });
644
+ expect(allXTrefs.xtrefs[0].referenceType).toBeUndefined();
645
+ expect(allXTrefs.xtrefs[0].sourceFile).toBeUndefined();
646
+ });
647
+ });
648
+
649
+ // Tests for ensuring alias data is properly maintained and not corrupted
650
+ describe('Bug fix: tref/xref alias caching issue', () => {
651
+
652
+ // Test: Are aliases properly preserved when references are updated?
653
+ it('should properly update aliases when tref changes from having aliases to no aliases', () => {
654
+ // First, process tref with aliases
655
+ const markdownWithAliases = "[[tref: KERISuite, composability, Kompoosabilitie, KPB]]";
656
+ let allXTrefs = { xtrefs: [] };
657
+
658
+ allXTrefs = addNewXTrefsFromMarkdown(markdownWithAliases, allXTrefs, 'composability.md', processXTrefObject);
659
+
660
+ expect(allXTrefs.xtrefs.length).toBe(1);
661
+ expect(allXTrefs.xtrefs[0]).toEqual({
662
+ externalSpec: 'KERISuite',
663
+ term: 'composability',
664
+ trefAliases: ['Kompoosabilitie', 'KPB'], xrefAliases: [],
665
+ firstTrefAlias: 'Kompoosabilitie',
666
+ sourceFiles: [{ file: 'composability.md', type: 'tref' }]
667
+ });
668
+
669
+ // Then, process the same tref without aliases - should update the existing entry
670
+ const markdownWithoutAliases = "[[tref: KERISuite, composability]]";
671
+
672
+ allXTrefs = addNewXTrefsFromMarkdown(markdownWithoutAliases, allXTrefs, 'composability.md', processXTrefObject);
673
+
674
+ expect(allXTrefs.xtrefs.length).toBe(1);
675
+ expect(allXTrefs.xtrefs[0]).toEqual({
676
+ externalSpec: 'KERISuite',
677
+ term: 'composability',
678
+ trefAliases: [], xrefAliases: [],
679
+ sourceFiles: [{ file: 'composability.md', type: 'tref' }]
680
+ });
681
+
682
+ // Verify firstTrefAlias property is completely removed
683
+ expect(allXTrefs.xtrefs[0].hasOwnProperty('firstTrefAlias')).toBe(false);
684
+ });
685
+
686
+ it('should preserve tref aliases when xref for same term is processed after tref', () => {
687
+ // First, process tref with aliases
688
+ const trefMarkdown = "[[tref: KERISuite, composability, Kompoosabilitie, KPB]]";
689
+ let allXTrefs = { xtrefs: [] };
690
+
691
+ allXTrefs = addNewXTrefsFromMarkdown(trefMarkdown, allXTrefs, 'composability.md', processXTrefObject);
692
+
693
+ // Then, process xref for same term (no aliases) - should NOT overwrite tref data
694
+ const xrefMarkdown = "[[xref: KERISuite, composability]]";
695
+
696
+ allXTrefs = addNewXTrefsFromMarkdown(xrefMarkdown, allXTrefs, 'soil.md', processXTrefObject);
697
+
698
+ expect(allXTrefs.xtrefs.length).toBe(1);
699
+ expect(allXTrefs.xtrefs[0]).toEqual({
700
+ externalSpec: 'KERISuite',
701
+ term: 'composability',
702
+ trefAliases: ['Kompoosabilitie', 'KPB'], xrefAliases: [], // Should be preserved from tref
703
+ firstTrefAlias: 'Kompoosabilitie', // Should be preserved from tref
704
+ sourceFiles: [
705
+ { file: 'composability.md', type: 'tref' },
706
+ { file: 'soil.md', type: 'xref' }
707
+ ]
300
708
  });
301
- expect(result.alias).toBeUndefined();
302
709
  });
303
710
  });