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
@@ -2,9 +2,9 @@
2
2
  "head": {
3
3
  "css": [
4
4
  "assets/css/theme-vars.css",
5
- "assets/css/bootstrap.min.css",
5
+ "assets/css/embedded-libraries/bootstrap.min.css",
6
6
  "assets/css/custom-elements.css",
7
- "assets/css/prism.css",
7
+ "assets/css/embedded-libraries/prism.css",
8
8
  "assets/css/chart.css",
9
9
  "assets/css/header-navbar.css",
10
10
  "assets/css/sidebar-toc.css",
@@ -15,10 +15,11 @@
15
15
  "assets/css/backToTop.css",
16
16
  "assets/css/notyf.css",
17
17
  "assets/css/collapse-definitions.css",
18
+ "assets/css/definition-buttons-container.css",
18
19
  "assets/css/create-term-filter.css",
19
20
  "assets/css/modal.css",
20
21
  "assets/css/create-alphabet-index.css",
21
- "assets/css/pdf-download.css",
22
+ "assets/css/download-pdf-docx.css",
22
23
  "assets/css/loader.css",
23
24
  "assets/css/external-links.css",
24
25
  "assets/css/repo-issues.css",
@@ -28,6 +29,7 @@
28
29
  "assets/css/horizontal-scroll-hint.css",
29
30
  "assets/css/highlight-heading-plus-sibling-nodes.css",
30
31
  "assets/css/counter.css",
32
+ "assets/css/insert-trefs.css",
31
33
  "assets/css/index.css"
32
34
  ],
33
35
  "js": [
@@ -41,41 +43,47 @@
41
43
  "node_modules/markdown-it/dist/markdown-it.min.js",
42
44
  "node_modules/markdown-it-deflist/dist/markdown-it-deflist.min.js",
43
45
  "assets/js/declare-markdown-it.js",
44
- "assets/js/prism.js",
45
- "assets/js/mermaid.js",
46
- "assets/js/chart.js",
47
- "assets/js/font-awesome.js",
48
- "assets/js/popper.js",
49
- "assets/js/tippy.js",
50
- "assets/js/diff.min.js",
46
+ "assets/js/embedded-libraries/prism.js",
47
+ "assets/js/embedded-libraries/mermaid.js",
48
+ "assets/js/embedded-libraries/chart.js",
49
+ "assets/js/embedded-libraries/font-awesome.js",
50
+ "assets/js/embedded-libraries/popper.js",
51
+ "assets/js/embedded-libraries/tippy.js",
52
+ "assets/js/embedded-libraries/diff.min.js",
51
53
  "assets/js/edit-term-buttons.js",
52
- "assets/js/hide-show-utility-container.js",
53
- "assets/js/create-alphabet-index.js",
54
- "assets/js/search.js",
54
+ "assets/js/terminology-section-utility-container/hide-show-utility-container.js",
55
+ "assets/js/terminology-section-utility-container/create-alphabet-index.js",
56
+ "assets/js/terminology-section-utility-container/create-term-filter.js",
57
+ "assets/js/terminology-section-utility-container/search.js",
58
+ "assets/js/terminology-section-utility-container.js",
55
59
  "assets/js/highlightMenuItems.js",
56
60
  "assets/js/collapsibleMenu.js",
57
61
  "assets/js/backToTop.js",
58
62
  "assets/js/addAnchorsToTerms.js",
59
63
  "assets/js/copyAnchorToCliboard.js",
60
- "assets/js/notyf.js",
64
+ "assets/js/embedded-libraries/notyf.js",
61
65
  "assets/js/modal.js",
62
66
  "assets/js/token-input.js",
63
- "assets/js/pdf-download.js",
67
+ "assets/js/download-pdf-docx.js",
64
68
  "assets/js/insert-trefs.js",
69
+ "assets/js/definition-button-container-utils.js",
65
70
  "assets/js/collapse-definitions.js",
66
- "assets/js/create-term-filter.js",
67
71
  "assets/js/collapse-meta-info.js",
68
72
  "assets/js/fix-last-dd.js",
69
73
  "assets/js/add-href-to-snapshot-link.js",
70
74
  "assets/js/adjust-font-size.js",
71
75
  "assets/js/toggle-dense-info.js",
72
76
  "assets/js/close-off-canvas-menu.js",
73
- "assets/js/index.js",
77
+ "assets/js/github-repo-info.js",
78
+ "assets/js/github-issues.js",
79
+ "assets/js/mermaid-diagrams.js",
80
+ "assets/js/charts.js",
81
+ "assets/js/tooltips.js",
74
82
  "assets/js/horizontal-scroll-hint.js",
75
83
  "assets/js/add-bootstrap-classes-to-images.js",
76
84
  "assets/js/image-full-size.js",
77
85
  "assets/js/highlight-heading-plus-sibling-nodes.js",
78
- "assets/js/bootstrap.bundle.min.js"
86
+ "assets/js/embedded-libraries/bootstrap.bundle.min.js"
79
87
  ]
80
88
  }
81
89
  }
package/index.js CHANGED
@@ -1,8 +1,28 @@
1
1
  const { initialize } = require('./src/init');
2
+ const Logger = require('./src/utils/logger');
2
3
 
3
4
  module.exports = async function (options = {}) {
4
5
  try {
5
- await initialize();
6
+ const { initializeConfig } = require('./src/pipeline/configuration/prepare-spec-configuration.js');
7
+ let toc = '';
8
+ global.toc = '';
9
+ const setToc = (html) => { toc = html || ''; global.toc = toc; };
10
+ let {
11
+ config,
12
+ externalSpecsList,
13
+ template,
14
+ assets,
15
+ externalReferences,
16
+ references,
17
+ definitions,
18
+ specGroups,
19
+ noticeTitles
20
+ } = await initializeConfig(options);
21
+
22
+ global.definitions = definitions;
23
+ global.references = references;
24
+ global.specGroups = specGroups;
25
+ global.noticeTitles = noticeTitles;
6
26
 
7
27
  const fs = require('fs-extra');
8
28
  const path = require('path');
@@ -11,390 +31,37 @@ module.exports = async function (options = {}) {
11
31
  const {
12
32
  fetchExternalSpecs,
13
33
  validateReferences,
14
- findExternalSpecByKey
15
- } = require('./src/references.js');
34
+ findExternalSpecByKey,
35
+ mergeXrefTermsIntoAllXTrefs
36
+ } = require('./src/pipeline/references/external-references-service.js');
16
37
 
17
- const { runJsonKeyValidatorSync } = require('./src/json-key-validator.js');
18
- runJsonKeyValidatorSync();
19
-
20
- const { createTermIndex } = require('./src/create-term-index.js');
21
- createTermIndex();
22
-
23
- const { processWithEscapes } = require('./src/escape-handler.js');
24
-
25
- const { insertTermIndex } = require('./src/insert-term-index.js');
26
- insertTermIndex();
38
+ const { processWithEscapes } = require('./src/pipeline/preprocessing/escape-processor.js');
39
+ const { processEscapedTags, restoreEscapedTags } = require('./src/pipeline/preprocessing/escape-placeholder-utils.js');
40
+ const { sortDefinitionTermsInHtml, fixDefinitionListStructure } = require('./src/pipeline/postprocessing/definition-list-postprocessor.js');
41
+ const { getGithubRepoInfo } = require('./src/utils/git-info.js');
27
42
 
28
43
  const findPkgDir = require('find-pkg-dir');
29
44
  const modulePath = findPkgDir(__dirname);
30
- let config = fs.readJsonSync('./.cache/specs-generated.json');
31
-
32
- const createExternalSpecsList = require('./src/create-external-specs-list.js');
33
-
34
- const externalSpecsList = createExternalSpecsList(config);
35
-
36
- const createVersionsIndex = require('./src/create-versions-index.js');
37
- createVersionsIndex(config.specs[0].output_path);
38
-
39
- const { fixMarkdownFiles } = require('./src/fix-markdown-files.js');
40
- const { processEscapedTags, restoreEscapedTags } = require('./src/escape-mechanism.js');
41
- const { sortDefinitionTermsInHtml, fixDefinitionListStructure } = require('./src/html-dom-processor.js');
42
-
43
- let template = fs.readFileSync(path.join(modulePath, 'templates/template.html'), 'utf8');
44
- let assets = fs.readJsonSync(modulePath + '/config/asset-map.json');
45
- let externalReferences;
46
- let references = [];
47
- let definitions = [];
48
- let toc;
49
- let specGroups = {};
50
- let noticeTitles = {};
51
-
52
- const noticeTypes = {
53
- note: 1,
54
- issue: 1,
55
- example: 1,
56
- warning: 1,
57
- todo: 1
58
- };
59
- const spaceRegex = /\s+/g;
60
- const specNameRegex = /^spec$|^spec-*\w+$/i;
61
- const terminologyRegex = /^def$|^ref$|^xref|^tref$/i;
62
- const specCorpus = fs.readJsonSync(modulePath + '/assets/compiled/refs.json');
63
- const containers = require('markdown-it-container');
64
-
65
- /*
66
- `const md` is assigned an instance of the markdown-it parser configured with various plugins and extensions. This instance (md) is intended to be used later to parse and render Markdown strings.
67
-
68
- The md function (which is an instance of the markdown-it parser) takes a Markdown string as its primary argument. It is called elsewhere as follows: `md.render(doc)`
69
- */
70
- const md = require('markdown-it')({
71
- html: true,
72
- linkify: true,
73
- typographer: true
74
- })
75
- /*
76
- Configures a Markdown-it plugin by passing it an array of extension objects, each responsible for handling specific custom syntax in Markdown documents.
77
- */
78
- .use(require('./src/markdown-it-extensions.js'), [
79
- /*
80
- The first extension (= the first configuration object = the first element of the array) focuses on terminology-related constructs, using a filter to match types against a regular expression (terminologyRegex).
81
- */
82
- {
83
- filter: type => type.match(terminologyRegex),
84
- parse(token, type, primary) {
85
- if (!primary) return;
86
- if (type === 'def') {
87
- definitions.push(token.info.args);
88
- return token.info.args.reduce((acc, syn) => {
89
- return `<span id="term:${syn.replace(spaceRegex, '-').toLowerCase()}">${acc}</span>`;
90
- }, primary);
91
- }
92
- else if (type === 'xref') {
93
- // Get the URL for the external specification reference, or default to '#' if not found
94
- const externalSpec = findExternalSpecByKey(config, token.info.args[0]);
95
- const url = externalSpec?.gh_page || '#';
96
-
97
- const term = token.info.args[1].replace(spaceRegex, '-').toLowerCase();
98
- return `<a class="x-term-reference term-reference" data-local-href="#term:${token.info.args[0]}:${term}"
99
- href="${url}#term:${term}">${token.info.args[1]}</a>`;
100
- }
101
- else if (type === 'tref') {
102
- // Support tref with optional alias: [[tref: spec, term, alias]]
103
- const termName = token.info.args[1];
104
- const alias = token.info.args[2]; // Optional alias
105
-
106
- // Create IDs for both the original term and the alias to enable referencing by either
107
- const termId = `term:${termName.replace(spaceRegex, '-').toLowerCase()}`;
108
- const aliasId = alias ? `term:${alias.replace(spaceRegex, '-').toLowerCase()}` : '';
109
-
110
- // Return the term structure similar to def, so it can be processed by markdown-it's definition list parser
111
- if (aliasId && alias !== termName) {
112
- return `<span class="transcluded-xref-term" id="${termId}"><span id="${aliasId}">${termName}</span></span>`;
113
- } else {
114
- return `<span class="transcluded-xref-term" id="${termId}">${termName}</span>`;
115
- }
116
- }
117
- else {
118
- references.push(primary);
119
- return `<a class="term-reference" href="#term:${primary.replace(spaceRegex, '-').toLowerCase()}">${primary}</a>`;
120
- }
121
- }
122
- },
123
- /*
124
- The second extension is designed for handling specification references.
125
- */
126
- {
127
- filter: type => type.match(specNameRegex),
128
- parse(token, type, name) {
129
- if (name) {
130
- let _name = name.replace(spaceRegex, '-').toUpperCase();
131
- let spec = specCorpus[_name] ||
132
- specCorpus[_name.toLowerCase()] ||
133
- specCorpus[name.toLowerCase()] ||
134
- specCorpus[name];
135
- if (spec) {
136
- spec._name = _name;
137
- let group = specGroups[type] = specGroups[type] || {};
138
- token.info.spec = group[_name] = spec;
139
- }
140
- }
141
- },
142
- render(token, type, name) {
143
- if (name) {
144
- let spec = token.info.spec;
145
- if (spec) return `[<a class="spec-reference" href="#ref:${spec._name}">${spec._name}</a>]`;
146
- }
147
- else return renderRefGroup(type);
148
- }
149
- }
150
- ])
151
- .use(require('markdown-it-attrs'))
152
- .use(require('markdown-it-chart').default)
153
- .use(require('markdown-it-deflist'))
154
- .use(require('markdown-it-references'))
155
- .use(require('markdown-it-icons').default, 'font-awesome')
156
- .use(require('markdown-it-ins'))
157
- .use(require('markdown-it-mark'))
158
- .use(require('markdown-it-textual-uml'))
159
- .use(require('markdown-it-sub'))
160
- .use(require('markdown-it-sup'))
161
- .use(require('markdown-it-task-lists'))
162
- .use(require('markdown-it-multimd-table'), {
163
- multiline: true,
164
- rowspan: true,
165
- headerless: true
166
- })
167
- .use(containers, 'notice', {
168
- validate: function (params) {
169
- let matches = params.match(/(\w+)\s?(.*)?/);
170
- return matches && noticeTypes[matches[1]];
171
- },
172
- render: function (tokens, idx) {
173
- let matches = tokens[idx].info.match(/(\w+)\s?(.*)?/);
174
- if (matches && tokens[idx].nesting === 1) {
175
- let id;
176
- let type = matches[1];
177
- if (matches[2]) {
178
- id = matches[2].trim().replace(/\s+/g, '-').toLowerCase();
179
- if (noticeTitles[id]) id += '-' + noticeTitles[id]++;
180
- else noticeTitles[id] = 1;
181
- }
182
- else id = type + '-' + noticeTypes[type]++;
183
- return `<div id="${id}" class="notice ${type}"><a class="notice-link" href="#${id}">${type.toUpperCase()}</a>`;
184
- }
185
- else return '</div>\n';
186
- }
187
- })
188
- .use(require('markdown-it-prism'))
189
- .use(require('markdown-it-toc-and-anchor').default, {
190
- tocClassName: 'toc',
191
- tocFirstLevel: 2,
192
- tocLastLevel: 4,
193
- tocCallback: (_md, _tokens, html) => toc = html,
194
- anchorLinkSymbol: '#', // was: §
195
- anchorClassName: 'toc-anchor d-print-none'
196
- })
197
- .use(require('@traptitech/markdown-it-katex'))
198
-
199
- const katexRules = ['math_block', 'math_inline'];
200
- const replacerRegex = /\[\[\s*([^\s[\]:]+):?\s*([^\]\n]+)?\]\]/img;
201
- const replacerArgsRegex = /\s*,+\s*/;
202
- const replacers = [
203
- {
204
- test: 'insert',
205
- transform: function (originalMatch, type, path) {
206
- if (!path) return '';
207
- return fs.readFileSync(path, 'utf8');
208
- }
209
- }
210
- ];
211
-
212
- // Synchronously process markdown files
213
- fixMarkdownFiles(path.join(config.specs[0].spec_directory, config.specs[0].spec_terms_directory));
214
-
215
- function createScriptElementWithXTrefDataForEmbeddingInHtml() {
216
- // Test if xtrefs-data.js exists, else make it an empty string
217
- const inputPath = path.join('.cache', 'xtrefs-data.js');
218
-
219
- let xtrefsData = '';
220
- if (fs.existsSync(inputPath)) {
221
- xtrefsData = '<script>' + fs.readFileSync(inputPath, 'utf8') + '</script>';
222
- }
223
-
224
- return xtrefsData;
225
- }
45
+ const { configurePlugins } = require('./src/markdown-it/plugins');
46
+ const {
47
+ katexRules,
48
+ replacerRegex,
49
+ replacerArgsRegex,
50
+ replacers,
51
+ createScriptElementWithXTrefDataForEmbeddingInHtml,
52
+ lookupXrefTerm,
53
+ applyReplacers,
54
+ normalizePath,
55
+ renderRefGroup,
56
+ findKatexDist
57
+ } = require('./src/pipeline/rendering/render-utils.js');
58
+
59
+ const { createMarkdownParser } = require('./src/pipeline/parsing/create-markdown-parser.js');
60
+ let md = createMarkdownParser(config, setToc);
226
61
 
227
62
  const xtrefsData = createScriptElementWithXTrefDataForEmbeddingInHtml();
228
63
 
229
- /**
230
- * Processes custom tag patterns in markdown content and applies transformation functions.
231
- *
232
- * This function scans the document for special tag patterns like [[tref:spec,term]]
233
- * and replaces them with the appropriate HTML using the matching replacer.
234
- *
235
- * For tref tags, this is where the magic happens - we intercept them before
236
- * the markdown parser even sees them, and convert them directly to HTML structure
237
- * that will integrate properly with definition lists.
238
- *
239
- * @param {string} doc - The markdown document to process
240
- * @returns {string} - The processed document with tags replaced by their HTML equivalents
241
- */
242
- function applyReplacers(doc) {
243
- // Use the escape handler for three-phase processing
244
- return processWithEscapes(doc, function(content) {
245
- return content.replace(replacerRegex, function (match, type, args) {
246
- let replacer = replacers.find(r => type.trim().match(r.test));
247
- if (replacer) {
248
- let argsArray = args ? args.trim().split(replacerArgsRegex) : [];
249
- return replacer.transform(match, type, ...argsArray);
250
- }
251
- return match;
252
- });
253
- });
254
- }
255
-
256
- function normalizePath(path) {
257
- return path.trim().replace(/\/$/g, '') + '/';
258
- }
259
-
260
- function renderRefGroup(type) {
261
- let group = specGroups[type];
262
- if (!group) return '';
263
-
264
- /*
265
- The key advantage of localeCompare over simple comparison operators (<, >) is that it:
266
-
267
- - Properly handles language-specific sorting rules (via locale settings)
268
- - Correctly compares strings containing special characters or accents
269
- - Can be configured to be case-insensitive
270
- */
271
- let html = Object.keys(group).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).reduce((html, name) => {
272
- let ref = group[name];
273
- return html += `
274
- <dt id="ref:${name}">${name}</dt>
275
- <dd>
276
- <cite><a href="${ref.href}">${ref.title}</a></cite>.
277
- ${ref.authors.join('; ')}; ${ref.rawDate}. <span class="reference-status">Status: ${ref.status}</span>.
278
- </dd>
279
- `;
280
- }, '<dl class="reference-list">');
281
- return `\n${html}\n</dl>\n`;
282
- }
283
-
284
- function findKatexDist() {
285
- const relpath = "node_modules/katex/dist";
286
- const paths = [
287
- path.join(process.cwd(), relpath),
288
- path.join(__dirname, relpath),
289
- ];
290
- for (const abspath of paths) {
291
- if (fs.existsSync(abspath)) {
292
- return abspath
293
- }
294
- }
295
- throw Error("katex distribution could not be located");
296
- }
297
-
298
- async function render(spec, assets) {
299
- try {
300
- noticeTitles = {};
301
- specGroups = {};
302
- console.log('ℹ️ Rendering: ' + spec.title);
303
-
304
- function interpolate(template, variables) {
305
- return template.replace(/\${(.*?)}/g, (match, p1) => variables[p1.trim()]);
306
- }
307
-
308
- // Add current date in 'DD Month YYYY' format for template injection
309
- const date = new Date();
310
- const day = String(date.getDate()).padStart(2, '0');
311
- const month = date.toLocaleString('en-US', { month: 'long' });
312
- const year = date.getFullYear();
313
- const currentDate = `${day} ${month} ${year}`;
314
-
315
- const docs = await Promise.all(
316
- (spec.markdown_paths || ['spec.md']).map(_path =>
317
- fs.readFile(spec.spec_directory + _path, 'utf8')
318
- )
319
- );
320
-
321
- const features = (({ source, logo }) => ({ source, logo }))(spec);
322
- if (spec.external_specs && !externalReferences) {
323
- externalReferences = await fetchExternalSpecs(spec);
324
- }
325
-
326
- // Find the index of the terms-and-definitions-intro.md file
327
- const termsIndex = (spec.markdown_paths || ['spec.md']).indexOf('terms-and-definitions-intro.md');
328
- if (termsIndex !== -1) {
329
- // Append the HTML string to the content of terms-and-definitions-intro.md. This string is used to create a div that is used to insert an alphabet index, and a div that is used as the starting point of the terminology index. The newlines are essential for the correct rendering of the markdown.
330
- docs[termsIndex] += '\n\n<div id="terminology-section-start"></div>\n\n';
331
- }
332
-
333
- let doc = docs.join("\n");
334
-
335
- // Handles backslash escape mechanism for substitution tags
336
- // Phase 1: Pre-processing - Handle escaped tags
337
- doc = processEscapedTags(doc);
338
-
339
- // Handles backslash escape mechanism for substitution tags
340
- // Phase 2: Tag Processing - Apply normal substitution logic
341
- doc = applyReplacers(doc);
342
-
343
- md[spec.katex ? "enable" : "disable"](katexRules);
344
-
345
- // `render` is the rendered HTML
346
- let renderedHtml = md.render(doc);
347
-
348
- // Apply the fix for broken definition list structures
349
- renderedHtml = fixDefinitionListStructure(renderedHtml);
350
-
351
- // Sort definition terms case-insensitively before final rendering
352
- renderedHtml = sortDefinitionTermsInHtml(renderedHtml);
353
-
354
- // Handles backslash escape mechanism for substitution tags
355
- // Phase 3: Post-processing - Restore escaped sequences as literals
356
- renderedHtml = restoreEscapedTags(renderedHtml);
357
-
358
- // Process external references to ensure they are inserted as raw HTML, not as JSON string
359
- const externalReferencesHtml = Array.isArray(externalReferences)
360
- ? externalReferences.join('')
361
- : (externalReferences || '');
362
-
363
- const templateInterpolated = interpolate(template, {
364
- title: spec.title,
365
- description: spec.description,
366
- author: spec.author,
367
- toc: toc,
368
- render: renderedHtml,
369
- assetsHead: assets.head,
370
- assetsBody: assets.body,
371
- assetsSvg: assets.svg,
372
- features: Object.keys(features).join(' '),
373
- externalReferences: externalReferencesHtml,
374
- xtrefsData: xtrefsData,
375
- specLogo: spec.logo,
376
- specFavicon: spec.favicon,
377
- specLogoLink: spec.logo_link,
378
- spec: JSON.stringify(spec),
379
- externalSpecsList: externalSpecsList,
380
- currentDate: currentDate
381
- });
382
-
383
- const outputPath = path.join(spec.destination, 'index.html');
384
- console.log('ℹ️ Attempting to write to:', outputPath);
385
-
386
- // Use promisified version instead of callback
387
- await fs.promises.writeFile(outputPath, templateInterpolated, 'utf8');
388
- console.log(`✅ Successfully wrote ${outputPath}`);
389
-
390
- validateReferences(references, definitions, renderedHtml);
391
- references = [];
392
- definitions = [];
393
- } catch (e) {
394
- console.error("❌ Render error: " + e.message);
395
- throw e;
396
- }
397
- }
64
+ const { render } = require('./src/pipeline/rendering/render-spec-document.js');
398
65
 
399
66
  try {
400
67
  config.specs.forEach(spec => {
@@ -404,20 +71,20 @@ module.exports = async function (options = {}) {
404
71
  if (!fs.existsSync(spec.destination)) {
405
72
  try {
406
73
  fs.mkdirSync(spec.destination, { recursive: true });
407
- console.log(`✅ Created directory: ${spec.destination}`);
74
+ Logger.success(`Created directory: ${spec.destination}`);
408
75
  } catch (error) {
409
- console.error(`❌ Failed to create directory ${spec.destination}: ${error.message}`);
76
+ Logger.error(`Failed to create directory ${spec.destination}: ${error.message}`);
410
77
  throw error;
411
78
  }
412
79
  } else {
413
- console.log(`ℹ️ Directory already exists: ${spec.destination}`);
80
+ Logger.info(`Directory already exists: ${spec.destination}`);
414
81
  }
415
82
 
416
83
  try {
417
84
  fs.ensureDirSync(spec.destination);
418
- console.log(`✅ Ensured directory is ready: ${spec.destination}`);
85
+ Logger.success(`Ensured directory is ready: ${spec.destination}`);
419
86
  } catch (error) {
420
- console.error(`❌ Failed to ensure directory ${spec.destination}: ${error.message}`);
87
+ Logger.error(`Failed to ensure directory ${spec.destination}: ${error.message}`);
421
88
  throw error;
422
89
  }
423
90
 
@@ -469,33 +136,33 @@ module.exports = async function (options = {}) {
469
136
  }
470
137
 
471
138
  // Run render and wait for it
472
- render(spec, assetTags)
139
+ render(spec, assetTags, { externalReferences, references, definitions, specGroups, noticeTitles }, config, template, assets, Logger, md, externalSpecsList)
473
140
  .then(() => {
474
- console.log('ℹ️ Render completed for:', spec.destination);
141
+ Logger.info('Render completed for:', spec.destination);
475
142
  if (options.nowatch) {
476
- console.log('ℹ️ Exiting with nowatch');
143
+ Logger.info('Exiting with nowatch');
477
144
  process.exit(0);
478
145
  }
479
146
  })
480
147
  .catch((e) => {
481
- console.error('Render failed:', e.message);
148
+ Logger.error('Render failed:', e.message);
482
149
  process.exit(1);
483
150
  });
484
151
 
485
152
  if (!options.nowatch) {
486
153
  gulp.watch(
487
154
  [spec.spec_directory + '**/*', '!' + path.join(spec.destination, 'index.html')],
488
- render.bind(null, spec, assetTags)
155
+ render.bind(null, spec, assetTags, { externalReferences, references, definitions, specGroups, noticeTitles }, config, template, assets, Logger, md, externalSpecsList)
489
156
  );
490
157
  }
491
158
 
492
159
  });
493
160
  } catch (error) {
494
- console.error(`Error during initialization or module execution: ${error.message}`);
161
+ Logger.error(`Error during initialization or module execution: ${error.message}`);
495
162
  throw error; // Re-throw to let the caller handle the error
496
163
  }
497
164
  } catch (error) {
498
- console.error(`Error during initialization: ${error.message}`);
165
+ Logger.error(`Error during initialization: ${error.message}`);
499
166
  throw error; // Re-throw to let the caller handle the error
500
167
  }
501
168
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-up-t",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Technical specification drafting tool that generates rich specification documents from markdown. Forked from https://github.com/decentralized-identity/spec-up by Daniel Buchner (https://github.com/csuwildcat)",
5
5
  "main": "./index",
6
6
  "repository": {
@@ -26,6 +26,8 @@
26
26
  "@octokit/plugin-throttling": "^9.4.0",
27
27
  "@traptitech/markdown-it-katex": "^3.3.0",
28
28
  "axios": "^1.7.7",
29
+ "chalk": "^4.1.2",
30
+ "cheerio": "^1.1.2",
29
31
  "dedent": "^1.5.3",
30
32
  "diff": "^7.0.0",
31
33
  "docx": "^8.5.0",
@@ -69,7 +71,8 @@
69
71
  },
70
72
  "devDependencies": {
71
73
  "jest": "^29.7.0",
72
- "jest-environment-jsdom": "^30.0.5"
74
+ "jest-environment-jsdom": "^30.0.5",
75
+ "unimported": "^1.31.0"
73
76
  },
74
77
  "scripts": {
75
78
  "test": "jest",