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.
- package/.github/copilot-instructions.md +13 -0
- package/assets/compiled/body.js +18 -12
- package/assets/compiled/head.css +8 -6
- package/assets/css/collapse-definitions.css +0 -1
- package/assets/css/counter.css +10 -22
- package/assets/css/create-pdf.css +4 -2
- package/assets/css/create-term-filter.css +4 -4
- package/assets/css/definition-buttons-container.css +60 -0
- package/assets/css/{pdf-download.css → download-pdf-docx.css} +9 -5
- package/assets/css/insert-trefs.css +7 -0
- package/assets/css/sidebar-toc.css +2 -1
- package/assets/css/terms-and-definitions.css +73 -22
- package/assets/js/add-href-to-snapshot-link.js +16 -9
- package/assets/js/addAnchorsToTerms.js +2 -2
- package/assets/js/charts.js +10 -0
- package/assets/js/collapse-definitions.js +13 -2
- package/assets/js/collapse-meta-info.js +11 -9
- package/assets/js/definition-button-container-utils.js +82 -0
- package/assets/js/download-pdf-docx.js +68 -0
- package/assets/js/edit-term-buttons.js +77 -20
- package/assets/js/github-issues.js +35 -0
- package/assets/js/github-repo-info.js +144 -0
- package/assets/js/highlight-heading-plus-sibling-nodes.test.js +18 -0
- package/assets/js/insert-trefs.js +62 -13
- package/assets/js/mermaid-diagrams.js +11 -0
- package/assets/js/terminology-section-utility-container/README.md +107 -0
- package/assets/js/terminology-section-utility-container/create-alphabet-index.js +17 -0
- package/assets/js/{create-term-filter.js → terminology-section-utility-container/create-term-filter.js} +11 -44
- package/assets/js/terminology-section-utility-container/hide-show-utility-container.js +21 -0
- package/assets/js/terminology-section-utility-container/search.js +203 -0
- package/assets/js/terminology-section-utility-container.js +203 -0
- package/assets/js/tooltips.js +283 -0
- package/config/asset-map.json +26 -18
- package/index.js +57 -390
- package/package.json +5 -2
- package/src/add-remove-xref-source.js +20 -21
- package/src/collect-external-references.js +8 -337
- package/src/collect-external-references.test.js +440 -33
- package/src/configure.js +8 -109
- package/src/create-docx.js +7 -6
- package/src/create-pdf.js +15 -14
- package/src/freeze-spec-data.js +46 -0
- package/src/git-info.test.js +76 -0
- package/src/health-check/destination-gitignore-checker.js +5 -3
- package/src/health-check/external-specs-checker.js +5 -4
- package/src/health-check/specs-configuration-checker.js +2 -1
- package/src/health-check/term-references-checker.js +5 -3
- package/src/health-check/terms-intro-checker.js +2 -1
- package/src/health-check/tref-term-checker.js +8 -7
- package/src/health-check.js +8 -7
- package/src/init.js +3 -2
- package/src/install-from-boilerplate/add-gitignore-entries.js +3 -2
- package/src/install-from-boilerplate/add-scripts-keys.js +5 -4
- package/src/install-from-boilerplate/boilerplate/.github/workflows/menu.yml +74 -97
- package/src/install-from-boilerplate/boilerplate/README.md +1 -1
- package/src/install-from-boilerplate/boilerplate/spec/example-markup-in-markdown.md +1 -1
- package/src/install-from-boilerplate/boilerplate/spec/spec-head.md +2 -2
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/composability.md +3 -0
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/compost.md +3 -0
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/fertilizer.md +3 -0
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/mulch.md +3 -0
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/pruning.md +3 -0
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/seedling.md +3 -0
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/soil.md +11 -0
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/watering.md +3 -0
- package/src/install-from-boilerplate/boilerplate/specs.json +24 -10
- package/src/install-from-boilerplate/config-scripts-keys.js +3 -3
- package/src/install-from-boilerplate/config-system-files.js +0 -1
- package/src/install-from-boilerplate/copy-boilerplate.js +2 -1
- package/src/install-from-boilerplate/copy-system-files.js +4 -3
- package/src/install-from-boilerplate/custom-update.js +12 -1
- package/src/install-from-boilerplate/help.txt +1 -1
- package/src/install-from-boilerplate/menu.sh +6 -6
- package/src/json-key-validator.js +17 -11
- package/src/markdown-it/README.md +207 -0
- package/src/markdown-it/definition-lists.js +397 -0
- package/src/markdown-it/index.js +83 -0
- package/src/markdown-it/link-enhancement.js +98 -0
- package/src/markdown-it/plugins.js +118 -0
- package/src/markdown-it/table-enhancement.js +97 -0
- package/src/markdown-it/template-tag-syntax.js +152 -0
- package/src/parsers/index.js +16 -0
- package/src/parsers/spec-parser.js +152 -0
- package/src/parsers/spec-parser.test.js +109 -0
- package/src/parsers/template-tag-parser.js +277 -0
- package/src/parsers/template-tag-parser.test.js +107 -0
- package/src/pipeline/configuration/configure-starterpack.js +200 -0
- package/src/{create-external-specs-list.js → pipeline/configuration/create-external-specs-list.js} +13 -12
- package/src/{create-term-index.js → pipeline/configuration/create-term-index.js} +19 -18
- package/src/{create-versions-index.js → pipeline/configuration/create-versions-index.js} +4 -3
- package/src/{insert-term-index.js → pipeline/configuration/insert-term-index.js} +2 -2
- package/src/pipeline/configuration/prepare-spec-configuration.js +70 -0
- package/src/pipeline/parsing/apply-markdown-it-extensions.js +35 -0
- package/src/pipeline/parsing/create-markdown-parser.js +94 -0
- package/src/pipeline/parsing/create-markdown-parser.test.js +49 -0
- package/src/{html-dom-processor.js → pipeline/postprocessing/definition-list-postprocessor.js} +69 -10
- package/src/{escape-handler.js → pipeline/preprocessing/escape-processor.js} +3 -1
- package/src/{fix-markdown-files.js → pipeline/preprocessing/normalize-terminology-markdown.js} +41 -31
- package/src/pipeline/references/collect-external-references.js +307 -0
- package/src/pipeline/references/external-references-service.js +231 -0
- package/src/pipeline/references/fetch-terms-from-index.js +198 -0
- package/src/pipeline/references/match-term.js +34 -0
- package/src/{collectExternalReferences/matchTerm.test.js → pipeline/references/match-term.test.js} +8 -2
- package/src/pipeline/references/process-xtrefs-data.js +94 -0
- package/src/pipeline/references/xtref-utils.js +166 -0
- package/src/pipeline/rendering/render-spec-document.js +146 -0
- package/src/pipeline/rendering/render-utils.js +154 -0
- package/src/utils/LOGGER.md +81 -0
- package/src/utils/{doesUrlExist.js → does-url-exist.js} +4 -3
- package/src/utils/fetch.js +5 -4
- package/src/utils/file-opener.js +3 -2
- package/src/utils/git-info.js +77 -0
- package/src/utils/logger.js +74 -0
- package/src/utils/regex-patterns.js +471 -0
- package/src/utils/regex-patterns.test.js +281 -0
- package/templates/template.html +56 -21
- package/assets/js/create-alphabet-index.js +0 -60
- package/assets/js/hide-show-utility-container.js +0 -16
- package/assets/js/index.js +0 -87
- package/assets/js/pdf-download.js +0 -46
- package/assets/js/search.js +0 -365
- package/src/collectExternalReferences/fetchTermsFromIndex.js +0 -284
- package/src/collectExternalReferences/matchTerm.js +0 -32
- package/src/collectExternalReferences/processXTrefsData.js +0 -108
- package/src/freeze.js +0 -90
- package/src/install-from-boilerplate/boilerplate/.github/workflows/fetch-and-push-xrefs.yml.old +0 -42
- package/src/install-from-boilerplate/boilerplate/.github/workflows/render-specs.yml +0 -47
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-1.md +0 -13
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-2.md +0 -3
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-3.md +0 -3
- package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-4.md +0 -3
- package/src/markdown-it-extensions.js +0 -395
- package/src/references.js +0 -114
- /package/assets/css/{bootstrap.min.css → embedded-libraries/bootstrap.min.css} +0 -0
- /package/assets/css/{prism.css → embedded-libraries/prism.css} +0 -0
- /package/assets/css/{prism.dark.css → embedded-libraries/prism.dark.css} +0 -0
- /package/assets/css/{prism.default.css → embedded-libraries/prism.default.css} +0 -0
- /package/assets/js/{bootstrap.bundle.min.js → embedded-libraries/bootstrap.bundle.min.js} +0 -0
- /package/assets/js/{chart.js → embedded-libraries/chart.js} +0 -0
- /package/assets/js/{diff.min.js → embedded-libraries/diff.min.js} +0 -0
- /package/assets/js/{font-awesome.js → embedded-libraries/font-awesome.js} +0 -0
- /package/assets/js/{mermaid.js → embedded-libraries/mermaid.js} +0 -0
- /package/assets/js/{notyf.js → embedded-libraries/notyf.js} +0 -0
- /package/assets/js/{popper.js → embedded-libraries/popper.js} +0 -0
- /package/assets/js/{prism.dark.js → embedded-libraries/prism.dark.js} +0 -0
- /package/assets/js/{prism.default.js → embedded-libraries/prism.default.js} +0 -0
- /package/assets/js/{prism.js → embedded-libraries/prism.js} +0 -0
- /package/assets/js/{tippy.js → embedded-libraries/tippy.js} +0 -0
- /package/src/{escape-mechanism.js → pipeline/preprocessing/escape-placeholder-utils.js} +0 -0
- /package/src/utils/{isLineWithDefinition.js → is-line-with-definition.js} +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Markdown-it Link Enhancement Module
|
|
5
|
+
*
|
|
6
|
+
* This module enhances link rendering by adding path-based attributes to anchor tags.
|
|
7
|
+
* These attributes can be used for CSS styling or JavaScript behavior based on the
|
|
8
|
+
* link's destination (domain, path segments, etc.).
|
|
9
|
+
*
|
|
10
|
+
* For example, a link to "https://example.com/docs/api" would get attributes like:
|
|
11
|
+
* - path-0="example.com"
|
|
12
|
+
* - path-1="docs"
|
|
13
|
+
* - path-2="api"
|
|
14
|
+
*
|
|
15
|
+
* This allows for targeted styling of links based on their destination.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Regular expression to extract domains and path segments from URLs
|
|
20
|
+
*
|
|
21
|
+
* This regex has two capture groups:
|
|
22
|
+
* - Group 1: Domain from http(s):// URLs (e.g., "example.com" from "https://example.com/path")
|
|
23
|
+
* - Group 2: Path segments from relative URLs (e.g., "docs" from "/docs/page")
|
|
24
|
+
*
|
|
25
|
+
* The 'g' flag enables global matching to find all segments in a URL.
|
|
26
|
+
*/
|
|
27
|
+
const pathSegmentRegex = /(?:http[s]*:\/\/([^\/]*)|(?:\/([^\/?]*)))/g;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Applies link enhancements to a markdown-it instance
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} md - The markdown-it instance to enhance
|
|
33
|
+
*
|
|
34
|
+
* This function overrides the default link_open and link_close renderers
|
|
35
|
+
* to add path-based attributes and special handling for auto-detected links.
|
|
36
|
+
*/
|
|
37
|
+
function applyLinkEnhancements(md) {
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Custom link_open renderer that adds path attributes
|
|
41
|
+
*
|
|
42
|
+
* @param {Array} tokens - Array of all tokens being processed
|
|
43
|
+
* @param {Number} idx - Index of the current link_open token
|
|
44
|
+
* @param {Object} options - Markdown-it options
|
|
45
|
+
* @param {Object} env - Environment/context object
|
|
46
|
+
* @param {Object} renderer - The renderer instance
|
|
47
|
+
* @returns {String} HTML string for the opening anchor tag with path attributes
|
|
48
|
+
*/
|
|
49
|
+
md.renderer.rules.link_open = function (tokens, idx, options, env, renderer) {
|
|
50
|
+
let token = tokens[idx];
|
|
51
|
+
|
|
52
|
+
// Process all attributes of the link token
|
|
53
|
+
let attrs = token.attrs.reduce((str, attr) => {
|
|
54
|
+
let name = attr[0]; // Attribute name (e.g., 'href', 'title')
|
|
55
|
+
let value = attr[1]; // Attribute value (e.g., 'https://example.com')
|
|
56
|
+
|
|
57
|
+
// Special processing for href attributes to add path information
|
|
58
|
+
if (name === 'href') {
|
|
59
|
+
let index = 0;
|
|
60
|
+
|
|
61
|
+
// Extract domain and path segments using the regex
|
|
62
|
+
value.replace(pathSegmentRegex, (match, domain, pathSegment) => {
|
|
63
|
+
// Add path-N attributes for each segment found
|
|
64
|
+
// domain OR pathSegment will be defined (not both, due to regex groups)
|
|
65
|
+
str += `path-${index++}="${domain || pathSegment}" `;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Add the original attribute to the string
|
|
70
|
+
str += `${name}="${value}" `;
|
|
71
|
+
return str;
|
|
72
|
+
}, '');
|
|
73
|
+
|
|
74
|
+
// Create the opening anchor tag with all attributes
|
|
75
|
+
let anchor = `<a ${attrs}>`;
|
|
76
|
+
|
|
77
|
+
// Special handling for auto-detected links (linkify plugin)
|
|
78
|
+
// These get an extra <span> wrapper for styling purposes
|
|
79
|
+
return token.markup === 'linkify' ? anchor + '<span>' : anchor;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Custom link_close renderer
|
|
84
|
+
*
|
|
85
|
+
* @param {Array} tokens - Array of all tokens being processed
|
|
86
|
+
* @param {Number} idx - Index of the current link_close token
|
|
87
|
+
* @param {Object} options - Markdown-it options
|
|
88
|
+
* @param {Object} env - Environment/context object
|
|
89
|
+
* @param {Object} renderer - The renderer instance
|
|
90
|
+
* @returns {String} HTML string for the closing anchor tag
|
|
91
|
+
*/
|
|
92
|
+
md.renderer.rules.link_close = function (tokens, idx, options, env, renderer) {
|
|
93
|
+
// Close the extra span for linkify links, or just close the anchor
|
|
94
|
+
return tokens[idx].markup === 'linkify' ? '</span></a>' : '</a>';
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = applyLinkEnhancements;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configures and applies external markdown-it plugins to a given markdown-it instance.
|
|
3
|
+
* This module centralizes plugin loading to reduce complexity in the main index.js file.
|
|
4
|
+
* It handles only the external npm plugins (e.g., markdown-it-attrs), not custom extensions.
|
|
5
|
+
*
|
|
6
|
+
* @param {Object} md - The markdown-it instance to configure
|
|
7
|
+
* @param {Object} config - Configuration object (e.g., for TOC anchor symbol)
|
|
8
|
+
* @param {Object} containers - The markdown-it-container instance (passed to avoid re-requiring)
|
|
9
|
+
* @param {Object} noticeTypes - Object defining valid notice types (e.g., { note: 1, issue: 1, ... })
|
|
10
|
+
* @param {Object} noticeTitles - Object to track notice titles (passed to maintain state)
|
|
11
|
+
* @returns {Object} The configured markdown-it instance
|
|
12
|
+
*/
|
|
13
|
+
function configurePlugins(md, config, containers, noticeTypes, noticeTitles, setToc) {
|
|
14
|
+
// Apply attribute support for elements (e.g., {.class} syntax)
|
|
15
|
+
// This enables adding CSS classes or IDs to markdown elements without HTML.
|
|
16
|
+
md.use(require('markdown-it-attrs'));
|
|
17
|
+
|
|
18
|
+
// Enable chart rendering from code blocks (e.g., ```chart ... ```)
|
|
19
|
+
// Useful for embedding diagrams directly in markdown.
|
|
20
|
+
md.use(require('markdown-it-chart').default);
|
|
21
|
+
|
|
22
|
+
// Support definition lists (e.g., term\n: definition)
|
|
23
|
+
// Enhances standard markdown with formal definition formatting.
|
|
24
|
+
md.use(require('markdown-it-deflist'));
|
|
25
|
+
|
|
26
|
+
// Add reference-style links and footnotes
|
|
27
|
+
// Allows cleaner link management in long documents.
|
|
28
|
+
md.use(require('markdown-it-references'));
|
|
29
|
+
|
|
30
|
+
// Enable Font Awesome icons (e.g., :fa-icon:)
|
|
31
|
+
// Integrates icon rendering for visual enhancements.
|
|
32
|
+
md.use(require('markdown-it-icons').default, 'font-awesome');
|
|
33
|
+
|
|
34
|
+
// Support <ins> tags for inserted text (e.g., ++text++)
|
|
35
|
+
// Useful for highlighting additions in specs.
|
|
36
|
+
md.use(require('markdown-it-ins'));
|
|
37
|
+
|
|
38
|
+
// Support <mark> tags for highlighted text (e.g., ==text==)
|
|
39
|
+
// Helps emphasize important terms or sections.
|
|
40
|
+
md.use(require('markdown-it-mark'));
|
|
41
|
+
|
|
42
|
+
// Enable textual UML diagrams (e.g., @startuml ... @enduml)
|
|
43
|
+
// Allows embedding diagrams without external tools.
|
|
44
|
+
md.use(require('markdown-it-textual-uml'));
|
|
45
|
+
|
|
46
|
+
// Support subscript text (e.g., H~2~O)
|
|
47
|
+
// Essential for scientific or technical writing.
|
|
48
|
+
md.use(require('markdown-it-sub'));
|
|
49
|
+
|
|
50
|
+
// Support superscript text (e.g., E=mc^2^)
|
|
51
|
+
// Complements subscript for mathematical expressions.
|
|
52
|
+
md.use(require('markdown-it-sup'));
|
|
53
|
+
|
|
54
|
+
// Enable task lists (e.g., - [x] Task)
|
|
55
|
+
// Great for checklists in documentation.
|
|
56
|
+
md.use(require('markdown-it-task-lists'));
|
|
57
|
+
|
|
58
|
+
// Support multi-line tables with rowspan/colspan
|
|
59
|
+
// Extends basic tables for complex layouts.
|
|
60
|
+
md.use(require('markdown-it-multimd-table'), {
|
|
61
|
+
multiline: true,
|
|
62
|
+
rowspan: true,
|
|
63
|
+
headerless: true
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Configure notice containers (e.g., ::: note ... :::)
|
|
67
|
+
// Uses the passed containers plugin for custom blocks like warnings or examples.
|
|
68
|
+
md.use(containers, 'notice', {
|
|
69
|
+
validate: function (params) {
|
|
70
|
+
// Check if the notice type is valid (e.g., 'note', 'issue')
|
|
71
|
+
let matches = params.match(/(\w+)\s?(.*)?/);
|
|
72
|
+
return matches && noticeTypes[matches[1]];
|
|
73
|
+
},
|
|
74
|
+
render: function (tokens, idx) {
|
|
75
|
+
// Render opening or closing tags for notices
|
|
76
|
+
let matches = tokens[idx].info.match(/(\w+)\s?(.*)?/);
|
|
77
|
+
if (matches && tokens[idx].nesting === 1) {
|
|
78
|
+
let id;
|
|
79
|
+
let type = matches[1];
|
|
80
|
+
if (matches[2]) {
|
|
81
|
+
// Custom ID from title
|
|
82
|
+
id = matches[2].trim().replace(/\s+/g, '-').toLowerCase();
|
|
83
|
+
if (noticeTitles[id]) id += '-' + noticeTitles[id]++;
|
|
84
|
+
else noticeTitles[id] = 1;
|
|
85
|
+
} else {
|
|
86
|
+
// Auto-generated ID
|
|
87
|
+
id = type + '-' + noticeTypes[type]++;
|
|
88
|
+
}
|
|
89
|
+
return `<div id="${id}" class="notice ${type}"><a class="notice-link" href="#${id}">${type.toUpperCase()}</a>`;
|
|
90
|
+
} else {
|
|
91
|
+
return '</div>\n';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Add syntax highlighting with Prism.js
|
|
97
|
+
// Enhances code blocks with colorized syntax.
|
|
98
|
+
md.use(require('markdown-it-prism'));
|
|
99
|
+
|
|
100
|
+
// Generate table of contents with anchors
|
|
101
|
+
// Automatically creates TOC from headings, with customizable symbols.
|
|
102
|
+
md.use(require('markdown-it-toc-and-anchor').default, {
|
|
103
|
+
tocClassName: 'toc',
|
|
104
|
+
tocFirstLevel: 2,
|
|
105
|
+
tocLastLevel: 4,
|
|
106
|
+
tocCallback: (_md, _tokens, html) => setToc(html),
|
|
107
|
+
anchorLinkSymbol: config.specs[0].anchor_symbol || '§',
|
|
108
|
+
anchorClassName: 'toc-anchor d-print-none'
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Enable KaTeX for math rendering (e.g., $$...$$)
|
|
112
|
+
// Supports inline and block math expressions.
|
|
113
|
+
md.use(require('@traptitech/markdown-it-katex'));
|
|
114
|
+
|
|
115
|
+
return md;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports = { configurePlugins };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Markdown-it Table Enhancement Module
|
|
5
|
+
*
|
|
6
|
+
* This module enhances the default table rendering by:
|
|
7
|
+
* 1. Adding Bootstrap CSS classes for styling (table, table-striped, table-bordered, table-hover)
|
|
8
|
+
* 2. Wrapping tables in a responsive container div for mobile-friendly display
|
|
9
|
+
*
|
|
10
|
+
* The markdown-it library uses a token-based rendering system where:
|
|
11
|
+
* - Tokens represent different parts of the markdown (table_open, table_close, etc.)
|
|
12
|
+
* - Renderer rules are functions that convert tokens to HTML
|
|
13
|
+
* - We override the default rules to add our custom behavior
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Applies table enhancements to a markdown-it instance
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} md - The markdown-it instance to enhance
|
|
20
|
+
*
|
|
21
|
+
* How this works:
|
|
22
|
+
* - Saves the original table_open and table_close renderers as fallbacks
|
|
23
|
+
* - Overrides them with custom functions that add Bootstrap classes and responsive wrapper
|
|
24
|
+
* - The table_open rule adds classes to the <table> element and opens a wrapper <div>
|
|
25
|
+
* - The table_close rule closes both the </table> and the wrapper </div>
|
|
26
|
+
*/
|
|
27
|
+
function applyTableEnhancements(md) {
|
|
28
|
+
// Store the original table renderers so we can call them after our modifications
|
|
29
|
+
// If no custom renderer exists, markdown-it provides a default self.renderToken function
|
|
30
|
+
const originalTableRender = md.renderer.rules.table_open || function (tokens, idx, options, env, self) {
|
|
31
|
+
return self.renderToken(tokens, idx, options);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const originalTableCloseRender = md.renderer.rules.table_close || function (tokens, idx, options, env, self) {
|
|
35
|
+
return self.renderToken(tokens, idx, options);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Custom table_open renderer
|
|
40
|
+
*
|
|
41
|
+
* @param {Array} tokens - Array of all tokens being processed
|
|
42
|
+
* @param {Number} idx - Index of the current table_open token
|
|
43
|
+
* @param {Object} options - Markdown-it options
|
|
44
|
+
* @param {Object} env - Environment/context object
|
|
45
|
+
* @param {Object} self - The renderer instance
|
|
46
|
+
* @returns {String} HTML string for the opening table with wrapper
|
|
47
|
+
*/
|
|
48
|
+
md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
|
|
49
|
+
// Get the current table token to modify its attributes
|
|
50
|
+
const token = tokens[idx];
|
|
51
|
+
|
|
52
|
+
// Find if the table already has a class attribute
|
|
53
|
+
const classIndex = token.attrIndex('class');
|
|
54
|
+
|
|
55
|
+
// Define the Bootstrap classes we want to add
|
|
56
|
+
const tableClasses = 'table table-striped table-bordered table-hover';
|
|
57
|
+
|
|
58
|
+
if (classIndex < 0) {
|
|
59
|
+
// No existing class attribute - add our classes
|
|
60
|
+
token.attrPush(['class', tableClasses]);
|
|
61
|
+
} else {
|
|
62
|
+
// Class attribute exists - append our classes if they're not already present
|
|
63
|
+
const existingClasses = token.attrs[classIndex][1];
|
|
64
|
+
|
|
65
|
+
// Filter out classes that are already present to avoid duplicates
|
|
66
|
+
const classesToAdd = tableClasses
|
|
67
|
+
.split(' ')
|
|
68
|
+
.filter(cls => !existingClasses.includes(cls))
|
|
69
|
+
.join(' ');
|
|
70
|
+
|
|
71
|
+
// Only append if we have new classes to add
|
|
72
|
+
if (classesToAdd) {
|
|
73
|
+
token.attrs[classIndex][1] = existingClasses + ' ' + classesToAdd;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Return the responsive wrapper div + the enhanced table opening tag
|
|
78
|
+
return '<div class="table-responsive-md">' + originalTableRender(tokens, idx, options, env, self);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Custom table_close renderer
|
|
83
|
+
*
|
|
84
|
+
* @param {Array} tokens - Array of all tokens being processed
|
|
85
|
+
* @param {Number} idx - Index of the current table_close token
|
|
86
|
+
* @param {Object} options - Markdown-it options
|
|
87
|
+
* @param {Object} env - Environment/context object
|
|
88
|
+
* @param {Object} self - The renderer instance
|
|
89
|
+
* @returns {String} HTML string for closing the table and wrapper
|
|
90
|
+
*/
|
|
91
|
+
md.renderer.rules.table_close = function (tokens, idx, options, env, self) {
|
|
92
|
+
// Close both the table and the responsive wrapper div
|
|
93
|
+
return originalTableCloseRender(tokens, idx, options, env, self) + '</div>';
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = applyTableEnhancements;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ESCAPED_PLACEHOLDER } = require('../pipeline/preprocessing/escape-processor.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Markdown-it Template-Tag Syntax Module
|
|
7
|
+
*
|
|
8
|
+
* This module adds support for custom template-tag syntax like [[ref:spec,term]] in markdown.
|
|
9
|
+
* It handles the parsing and rendering of these special constructs.
|
|
10
|
+
*
|
|
11
|
+
* Template-tag syntax format: [[type:arg1,arg2,arg3]]
|
|
12
|
+
* Examples:
|
|
13
|
+
* - [[def:term,alias]] - Define a term with an alias
|
|
14
|
+
* - [[tref:external-spec,term]] - Reference a term from external specification
|
|
15
|
+
* - [[xref:spec,term]] - Cross-reference to another specification
|
|
16
|
+
*
|
|
17
|
+
* The module works in two phases:
|
|
18
|
+
* 1. PARSING: Scans markdown text for [[...]] patterns and creates template-tag tokens
|
|
19
|
+
* 2. RENDERING: Converts template-tag tokens to final HTML using template-tag handlers
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration constants for template-tag syntax
|
|
24
|
+
* These define the delimiters and parsing rules for template-tag markers
|
|
25
|
+
*/
|
|
26
|
+
const { templateTags } = require('../utils/regex-patterns');
|
|
27
|
+
|
|
28
|
+
const levels = 2; // Number of bracket characters (e.g., 2 = [[]])
|
|
29
|
+
const openString = '['.repeat(levels); // Opening delimiter: '[['
|
|
30
|
+
const closeString = ']'.repeat(levels); // Closing delimiter: ']]'
|
|
31
|
+
|
|
32
|
+
// Regular expression to extract template-tag components from [[type:args]] syntax
|
|
33
|
+
// Group 1: template-tag type (e.g., 'ref', 'tref', 'def')
|
|
34
|
+
// Group 2: arguments (everything after the colon, comma-separated)
|
|
35
|
+
const contentRegex = templateTags.content;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Applies template-tag syntax support to a markdown-it instance
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} md - The markdown-it instance to enhance
|
|
41
|
+
* @param {Array} templates - Array of template-tag handler objects
|
|
42
|
+
*
|
|
43
|
+
* Each template-tag handler should have:
|
|
44
|
+
* - filter(type): function that returns true if this handler processes the given type
|
|
45
|
+
* - parse(token, type, ...args): optional preprocessing function
|
|
46
|
+
* - render(token, type, ...args): function that returns HTML string
|
|
47
|
+
*/
|
|
48
|
+
function applyTemplateTagSyntax(md, templates = []) {
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Custom inline parsing rule for template-tag syntax
|
|
52
|
+
*
|
|
53
|
+
* This rule is added to markdown-it's inline ruler (which processes inline elements)
|
|
54
|
+
* and runs after the 'emphasis' rule to handle our [[template-tag]] syntax.
|
|
55
|
+
*
|
|
56
|
+
* @param {Object} state - Parser state object containing source text and position
|
|
57
|
+
* @param {Boolean} silent - If true, don't modify state (used for validation)
|
|
58
|
+
* @returns {Boolean} true if template-tag was found and processed, false otherwise
|
|
59
|
+
*/
|
|
60
|
+
function templates_ruler(state, silent) {
|
|
61
|
+
// Get current position in the source text
|
|
62
|
+
var start = state.pos;
|
|
63
|
+
|
|
64
|
+
// Skip processing if we're at an escaped placeholder (handled by escape mechanism)
|
|
65
|
+
if (state.src.slice(start, start + ESCAPED_PLACEHOLDER.length) === ESCAPED_PLACEHOLDER) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check if we're at the start of a template-tag marker [[
|
|
70
|
+
let prefix = state.src.slice(start, start + levels);
|
|
71
|
+
if (prefix !== openString) {
|
|
72
|
+
return false; // Not a template-tag, let other rules handle it
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Find the matching closing marker ]]
|
|
76
|
+
var indexOfClosingBrace = state.src.indexOf(closeString, start);
|
|
77
|
+
|
|
78
|
+
if (indexOfClosingBrace > 0) {
|
|
79
|
+
// Extract the content between [[ and ]]
|
|
80
|
+
let templateTagContent = state.src.slice(start + levels, indexOfClosingBrace);
|
|
81
|
+
|
|
82
|
+
// Parse the template-tag content using regex
|
|
83
|
+
let match = contentRegex.exec(templateTagContent);
|
|
84
|
+
if (!match) {
|
|
85
|
+
return false; // Invalid template-tag syntax
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Extract template-tag type and arguments
|
|
89
|
+
let type = match[1];
|
|
90
|
+
let template = templates.find(t => t.filter(type) && t);
|
|
91
|
+
|
|
92
|
+
if (!template) {
|
|
93
|
+
return false; // No handler found for this template-tag type
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Parse arguments (comma-separated list)
|
|
97
|
+
let args = match[2] ? match[2].trim().split(/\s*,+\s*/) : [];
|
|
98
|
+
|
|
99
|
+
// Create a new template-tag token in the token stream
|
|
100
|
+
// This token will be processed later during rendering
|
|
101
|
+
let token = state.push('template', '', 0);
|
|
102
|
+
token.content = match[0]; // Store original matched content
|
|
103
|
+
token.info = { type, template, args }; // Store parsed information
|
|
104
|
+
|
|
105
|
+
// If the template-tag has a parse function, call it for preprocessing
|
|
106
|
+
// This allows template-tags to modify their content during parsing
|
|
107
|
+
if (template.parse) {
|
|
108
|
+
token.content = template.parse(token, type, ...args) || token.content;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Move parser position past the template-tag
|
|
112
|
+
state.pos = indexOfClosingBrace + levels;
|
|
113
|
+
return true; // Template-tag successfully processed
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return false; // No closing marker found
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Register the template-tag parsing rule with markdown-it
|
|
120
|
+
// It runs after 'emphasis' to ensure proper precedence
|
|
121
|
+
md.inline.ruler.after('emphasis', 'templates', templates_ruler);
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Renderer for template-tag tokens
|
|
125
|
+
*
|
|
126
|
+
* This function is called during the rendering phase to convert
|
|
127
|
+
* template-tag tokens into their final HTML representation.
|
|
128
|
+
*
|
|
129
|
+
* @param {Array} tokens - Array of all tokens being rendered
|
|
130
|
+
* @param {Number} idx - Index of current template-tag token
|
|
131
|
+
* @param {Object} options - Markdown-it options
|
|
132
|
+
* @param {Object} env - Environment/context object
|
|
133
|
+
* @param {Object} renderer - The renderer instance
|
|
134
|
+
* @returns {String} HTML string for this template-tag
|
|
135
|
+
*/
|
|
136
|
+
md.renderer.rules.template = function (tokens, idx, options, env, renderer) {
|
|
137
|
+
let token = tokens[idx];
|
|
138
|
+
let template = token.info.template;
|
|
139
|
+
|
|
140
|
+
// Call the template-tag's render function if it exists
|
|
141
|
+
if (template.render) {
|
|
142
|
+
let result = template.render(token, token.info.type, ...token.info.args);
|
|
143
|
+
// Return the rendered result, or fall back to original syntax if render fails
|
|
144
|
+
return result || (openString + token.content + closeString);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// No render function - return the content as-is
|
|
148
|
+
return token.content;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = applyTemplateTagSyntax;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsers Module Index - Functional Style
|
|
3
|
+
*
|
|
4
|
+
* This module provides a centralized export point for all parser functions.
|
|
5
|
+
* It promotes clean imports and consistent API access across the codebase.
|
|
6
|
+
* The functional approach provides better tree-shaking and simpler testing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const templateTagParser = require('./template-tag-parser');
|
|
10
|
+
const specParser = require('./spec-parser');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
// Parser factory functions
|
|
14
|
+
createTemplateTagParser: templateTagParser.createTemplateTagParser,
|
|
15
|
+
createSpecParser: specParser.createSpecParser
|
|
16
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specification Parser - Functional Style
|
|
3
|
+
*
|
|
4
|
+
* This module provides pure functions for processing specification-related markdown extensions:
|
|
5
|
+
* - [[spec: name]] - Individual specification references
|
|
6
|
+
* - [[spec-*: name]] - Grouped specification references (e.g., spec-normative, spec-informative)
|
|
7
|
+
*
|
|
8
|
+
* The functional approach isolates specification logic from terminology concerns,
|
|
9
|
+
* reducing cognitive complexity and improving maintainability through pure functions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { renderRefGroup } = require('../pipeline/rendering/render-utils.js');
|
|
13
|
+
const { whitespace } = require('../utils/regex-patterns');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Normalizes a specification name for consistent lookup
|
|
17
|
+
* @param {string} name - The original specification name
|
|
18
|
+
* @returns {string} The normalized name (uppercase with hyphens)
|
|
19
|
+
*/
|
|
20
|
+
function normalizeSpecName(name) {
|
|
21
|
+
return name.replace(whitespace.oneOrMore, '-').toUpperCase();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Looks up a specification in the corpus using various name formats
|
|
26
|
+
* @param {Object} specCorpus - The specification corpus
|
|
27
|
+
* @param {string} name - The specification name to look up
|
|
28
|
+
* @returns {Object|null} The found specification or null
|
|
29
|
+
*/
|
|
30
|
+
function findSpecInCorpus(specCorpus, name) {
|
|
31
|
+
const normalizedName = normalizeSpecName(name);
|
|
32
|
+
|
|
33
|
+
return specCorpus[normalizedName] ||
|
|
34
|
+
specCorpus[normalizedName.toLowerCase()] ||
|
|
35
|
+
specCorpus[name.toLowerCase()] ||
|
|
36
|
+
specCorpus[name] ||
|
|
37
|
+
null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Processes specification reference tokens during parsing phase
|
|
42
|
+
* Looks up specification details and stores them for later rendering
|
|
43
|
+
* @param {Object} specCorpus - The loaded specification corpus
|
|
44
|
+
* @param {Object} globalState - Global state object containing specGroups
|
|
45
|
+
* @param {Object} token - The markdown-it token being processed
|
|
46
|
+
* @param {string} type - The type of spec construct (e.g., 'spec', 'spec-normative')
|
|
47
|
+
* @param {string} name - The specification name to look up
|
|
48
|
+
*/
|
|
49
|
+
function parseSpecReference(specCorpus, globalState, token, type, name) {
|
|
50
|
+
if (!name) return;
|
|
51
|
+
|
|
52
|
+
const spec = findSpecInCorpus(specCorpus, name);
|
|
53
|
+
|
|
54
|
+
if (spec) {
|
|
55
|
+
// Store the normalized name for consistent referencing
|
|
56
|
+
const normalizedName = normalizeSpecName(name);
|
|
57
|
+
spec._name = normalizedName;
|
|
58
|
+
|
|
59
|
+
// Organize specifications by type/group for rendering
|
|
60
|
+
const group = globalState.specGroups[type] = globalState.specGroups[type] || {};
|
|
61
|
+
token.info.spec = group[normalizedName] = spec;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Renders an individual specification reference as a link
|
|
67
|
+
* @param {Object} token - The token containing spec information
|
|
68
|
+
* @returns {string} HTML anchor element linking to the specification
|
|
69
|
+
*/
|
|
70
|
+
function renderIndividualSpec(token) {
|
|
71
|
+
const spec = token.info.spec;
|
|
72
|
+
if (!spec) return '';
|
|
73
|
+
|
|
74
|
+
// Create a reference link to the specification
|
|
75
|
+
// The href uses a 'ref:' prefix to distinguish from term references
|
|
76
|
+
return `[<a class="spec-reference" href="#ref:${spec._name}">${spec._name}</a>]`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Renders a group of specifications as a formatted list
|
|
81
|
+
* @param {string} type - The specification group type
|
|
82
|
+
* @param {Object} specGroups - The global specGroups object
|
|
83
|
+
* @returns {string} HTML representation of the specification group
|
|
84
|
+
*/
|
|
85
|
+
function renderSpecGroup(type, specGroups) {
|
|
86
|
+
// Delegate to the render utility which handles the complex group formatting
|
|
87
|
+
return renderRefGroup(type, specGroups);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Renders specification references during the rendering phase
|
|
92
|
+
* Creates either individual spec links or grouped spec lists
|
|
93
|
+
* @param {Object} specGroups - The global specGroups object
|
|
94
|
+
* @param {Object} token - The markdown-it token being rendered
|
|
95
|
+
* @param {string} type - The type of spec construct
|
|
96
|
+
* @param {string} name - The specification name (if individual reference)
|
|
97
|
+
* @returns {string} HTML for the specification reference or group
|
|
98
|
+
*/
|
|
99
|
+
function renderSpecReference(specGroups, token, type, name) {
|
|
100
|
+
if (name) {
|
|
101
|
+
// Render individual specification reference
|
|
102
|
+
return renderIndividualSpec(token);
|
|
103
|
+
} else {
|
|
104
|
+
// Render grouped specification references (when no specific name is provided)
|
|
105
|
+
return renderSpecGroup(type, specGroups);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Gets all specifications in a specific group
|
|
111
|
+
* Utility function for accessing grouped specifications
|
|
112
|
+
* @param {Object} specGroups - The global specGroups object
|
|
113
|
+
* @param {string} type - The specification group type
|
|
114
|
+
* @returns {Object} Object containing all specs in the group
|
|
115
|
+
*/
|
|
116
|
+
function getSpecGroup(specGroups, type) {
|
|
117
|
+
return specGroups[type] || {};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Checks if a specification exists in the corpus
|
|
122
|
+
* @param {Object} specCorpus - The specification corpus
|
|
123
|
+
* @param {string} name - The specification name to check
|
|
124
|
+
* @returns {boolean} True if the specification exists
|
|
125
|
+
*/
|
|
126
|
+
function hasSpec(specCorpus, name) {
|
|
127
|
+
return findSpecInCorpus(specCorpus, name) !== null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Creates a specification parser function with bound corpus and global state.
|
|
132
|
+
* This provides a clean interface similar to the class-based approach but with functional benefits.
|
|
133
|
+
* @param {Object} specCorpus - The specification corpus
|
|
134
|
+
* @param {Object} globalState - Global state object
|
|
135
|
+
* @returns {Object} An object with parser and renderer functions
|
|
136
|
+
*/
|
|
137
|
+
function createSpecParser(specCorpus, globalState) {
|
|
138
|
+
return {
|
|
139
|
+
parseSpecReference: (token, type, name) => parseSpecReference(specCorpus, globalState, token, type, name),
|
|
140
|
+
renderSpecReference: (token, type, name) => renderSpecReference(globalState.specGroups, token, type, name),
|
|
141
|
+
hasSpec: (name) => hasSpec(specCorpus, name),
|
|
142
|
+
getSpecGroup: (type) => getSpecGroup(globalState.specGroups, type)
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = {
|
|
147
|
+
createSpecParser,
|
|
148
|
+
// Export individual functions for testing purposes
|
|
149
|
+
parseSpecReference,
|
|
150
|
+
renderIndividualSpec,
|
|
151
|
+
hasSpec
|
|
152
|
+
};
|