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,207 @@
|
|
|
1
|
+
# Markdown-it Extensions
|
|
2
|
+
|
|
3
|
+
This directory contains the refactored markdown-it extensions used by the spec-up-t system. The extensions have been broken down into focused, well-documented modules to improve maintainability and understanding.
|
|
4
|
+
|
|
5
|
+
## Module Overview
|
|
6
|
+
|
|
7
|
+
### Core Philosophy
|
|
8
|
+
|
|
9
|
+
The markdown-it library uses a token-based rendering system where:
|
|
10
|
+
|
|
11
|
+
- **Tokens** represent different parts of the markdown (paragraphs, headers, tables, etc.)
|
|
12
|
+
- **Renderer rules** are functions that convert tokens to HTML
|
|
13
|
+
- **Inline rules** process inline elements during parsing
|
|
14
|
+
- **Plugins** extend the parser with custom functionality
|
|
15
|
+
|
|
16
|
+
Our extensions override default renderer rules and add custom inline parsing rules to implement spec-up-specific functionality.
|
|
17
|
+
|
|
18
|
+
## Modules
|
|
19
|
+
|
|
20
|
+
### 1. `table-enhancement.js`
|
|
21
|
+
|
|
22
|
+
**Purpose**: Enhances table rendering with Bootstrap styling and responsive wrappers.
|
|
23
|
+
|
|
24
|
+
**Features**:
|
|
25
|
+
|
|
26
|
+
- Adds Bootstrap CSS classes (`table`, `table-striped`, `table-bordered`, `table-hover`)
|
|
27
|
+
- Wraps tables in responsive containers (`table-responsive-md`)
|
|
28
|
+
- Preserves existing classes while adding new ones
|
|
29
|
+
|
|
30
|
+
**How it works**: Overrides `table_open` and `table_close` renderer rules.
|
|
31
|
+
|
|
32
|
+
### 2. `template-tag-syntax.js`
|
|
33
|
+
|
|
34
|
+
**Purpose**: Processes custom template-tag syntax like `[[def:term]]`, `[[tref:spec,term]]`, etc.
|
|
35
|
+
|
|
36
|
+
**Features**:
|
|
37
|
+
|
|
38
|
+
- Parses `[[type:arg1,arg2]]` syntax during markdown processing
|
|
39
|
+
- Creates template tokens for later rendering
|
|
40
|
+
- Supports extensible template-tag handlers
|
|
41
|
+
- Integrates with the escape mechanism
|
|
42
|
+
|
|
43
|
+
**How it works**:
|
|
44
|
+
|
|
45
|
+
- Adds an inline ruler (`templates_ruler`) to detect and parse template-tag syntax
|
|
46
|
+
- Creates template tokens with parsed information
|
|
47
|
+
- Provides a renderer rule to convert template tokens to HTML
|
|
48
|
+
|
|
49
|
+
### 3. `link-enhancement.js`
|
|
50
|
+
|
|
51
|
+
**Purpose**: Adds path-based attributes to links for CSS styling and JavaScript targeting.
|
|
52
|
+
|
|
53
|
+
**Features**:
|
|
54
|
+
|
|
55
|
+
- Extracts domain and path segments from URLs
|
|
56
|
+
- Adds `path-0`, `path-1`, etc. attributes to anchor tags
|
|
57
|
+
- Special handling for auto-detected links (linkify)
|
|
58
|
+
|
|
59
|
+
**How it works**: Overrides `link_open` and `link_close` renderer rules.
|
|
60
|
+
|
|
61
|
+
### 4. `definition-lists.js`
|
|
62
|
+
|
|
63
|
+
**Purpose**: Advanced processing of definition lists for terminology and reference management.
|
|
64
|
+
|
|
65
|
+
**Features**:
|
|
66
|
+
|
|
67
|
+
- **Smart Classification**: Distinguishes between terminology lists and reference lists
|
|
68
|
+
- **Term Type Detection**: Identifies local terms (`[[def:term]]`) vs external terms (`[[tref:spec,term]]`)
|
|
69
|
+
- **Quality Control**: Removes empty `<dt>` elements that cause rendering issues
|
|
70
|
+
- **Section-Aware**: Only applies terminology styling after the terminology section marker
|
|
71
|
+
|
|
72
|
+
**How it works**:
|
|
73
|
+
|
|
74
|
+
- Overrides `dl_open`, `dt_open`, and `dt_close` renderer rules
|
|
75
|
+
- Uses helper functions to analyze token structure and content
|
|
76
|
+
- Applies CSS classes based on term types and context
|
|
77
|
+
|
|
78
|
+
### 5. `index.js`
|
|
79
|
+
|
|
80
|
+
**Purpose**: Main orchestrator that applies all enhancements in the correct order.
|
|
81
|
+
|
|
82
|
+
**Features**:
|
|
83
|
+
|
|
84
|
+
- Single entry point for all markdown-it extensions
|
|
85
|
+
- Maintains dependency order between modules
|
|
86
|
+
- Provides both unified and individual module access
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
### Basic Usage
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
const MarkdownIt = require('markdown-it');
|
|
94
|
+
const applyMarkdownItExtensions = require('./markdown-it');
|
|
95
|
+
|
|
96
|
+
const md = new MarkdownIt();
|
|
97
|
+
const templates = [
|
|
98
|
+
{
|
|
99
|
+
filter: type => type === 'def',
|
|
100
|
+
render: (token, type, term) => `<span id="term:${term}">${term}</span>`
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
applyMarkdownItExtensions(md, templates);
|
|
105
|
+
const html = md.render('[[def:example-term]]');
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Individual Module Usage
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const applyTableEnhancements = require('./markdown-it/table-enhancement');
|
|
112
|
+
const applyTemplateTagSyntax = require('./markdown-it/template-tag-syntax');
|
|
113
|
+
|
|
114
|
+
// Apply only table enhancements
|
|
115
|
+
applyTableEnhancements(md);
|
|
116
|
+
|
|
117
|
+
// Apply only template-tag syntax with custom handlers
|
|
118
|
+
applyTemplateTagSyntax(md, templates);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Template System
|
|
122
|
+
|
|
123
|
+
The template-tag system processes custom syntax like `[[type:args]]` in markdown. Template-tags are defined as objects with:
|
|
124
|
+
|
|
125
|
+
- `filter(type)`: Function that returns true if this handler processes the given type
|
|
126
|
+
- `parse(token, type, ...args)`: Optional preprocessing function called during parsing
|
|
127
|
+
- `render(token, type, ...args)`: Function that returns HTML string for rendering
|
|
128
|
+
|
|
129
|
+
### Example Template-Tag Handler
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
{
|
|
133
|
+
filter: type => type.match(/^def$/),
|
|
134
|
+
parse: (token, type, term, alias) => {
|
|
135
|
+
// Preprocessing during markdown parsing
|
|
136
|
+
definitions.push([term, alias]);
|
|
137
|
+
return `<span id="term:${term.replace(/\s+/g, '-').toLowerCase()}">${term}</span>`;
|
|
138
|
+
},
|
|
139
|
+
render: (token, type, ...args) => {
|
|
140
|
+
// Final rendering (if parse didn't handle it)
|
|
141
|
+
return token.content;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Definition List Processing
|
|
147
|
+
|
|
148
|
+
The definition list module implements sophisticated logic for handling terminology:
|
|
149
|
+
|
|
150
|
+
### List Classification
|
|
151
|
+
|
|
152
|
+
- **Terminology Lists**: Get `terms-and-definitions-list` class
|
|
153
|
+
- **Reference Lists**: Keep existing classes (e.g., `reference-list`)
|
|
154
|
+
- **Section-Aware**: Only processes lists after `terminology-section-start` marker
|
|
155
|
+
|
|
156
|
+
### Term Classification
|
|
157
|
+
|
|
158
|
+
- **Local Terms** (`[[def:term]]`): Get `term-local` class
|
|
159
|
+
- **External Terms** (`[[tref:spec,term]]`): Get `term-external` class
|
|
160
|
+
- **Regular Terms**: No special class
|
|
161
|
+
|
|
162
|
+
### Quality Control
|
|
163
|
+
|
|
164
|
+
- **Empty Elements**: Removes `<dt>` elements with no content
|
|
165
|
+
- **Spec References**: Avoids styling bibliographic references as terminology
|
|
166
|
+
|
|
167
|
+
## Development Guidelines
|
|
168
|
+
|
|
169
|
+
### Adding New Modules
|
|
170
|
+
|
|
171
|
+
1. Create a focused module in this directory
|
|
172
|
+
2. Follow the existing naming pattern (`feature-name.js`)
|
|
173
|
+
3. Export a single function that takes a markdown-it instance
|
|
174
|
+
4. Add comprehensive documentation with examples
|
|
175
|
+
5. Update `index.js` to include the new module
|
|
176
|
+
|
|
177
|
+
### Code Quality
|
|
178
|
+
|
|
179
|
+
- Keep cognitive complexity below 15
|
|
180
|
+
- Add extensive comments for markdown-it concepts
|
|
181
|
+
- Use descriptive function and variable names
|
|
182
|
+
- Extract helper functions for complex logic
|
|
183
|
+
- Write tests for new functionality
|
|
184
|
+
|
|
185
|
+
### SonarQube Compliance
|
|
186
|
+
|
|
187
|
+
All modules must pass SonarQube analysis without issues. The refactoring specifically addresses:
|
|
188
|
+
|
|
189
|
+
- Reduced cognitive complexity through modularization
|
|
190
|
+
- Better code organization and separation of concerns
|
|
191
|
+
- Comprehensive documentation for maintainability
|
|
192
|
+
|
|
193
|
+
## Backward Compatibility
|
|
194
|
+
|
|
195
|
+
The main `markdown-it-extensions.js` file maintains complete backward compatibility by delegating to the new modular system. Existing code can continue to use the original interface without changes.
|
|
196
|
+
|
|
197
|
+
## Testing
|
|
198
|
+
|
|
199
|
+
Run the full test suite to ensure all functionality works correctly:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
npm test
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Individual modules can be tested by importing and using them directly in test files.
|
|
206
|
+
|
|
207
|
+
Please remember to run `gulp compile` after making changes to client-side assets, and test on a separate test machine before deployment.
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { htmlComments } = require('../utils/regex-patterns');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Markdown-it Definition Lists Enhancement Module
|
|
7
|
+
*
|
|
8
|
+
* This module provides sophisticated enhancements for definition lists (<dl>) in markdown.
|
|
9
|
+
* It handles several key aspects of definition list processing in the spec-up system:
|
|
10
|
+
*
|
|
11
|
+
* 1. TERMINOLOGY CLASSIFICATION: Distinguishes between different types of definition lists:
|
|
12
|
+
* - Terms and definitions lists (terminology sections)
|
|
13
|
+
* - Specification reference lists (bibliographic references)
|
|
14
|
+
*
|
|
15
|
+
* 2. TERM TYPE DETECTION: Identifies and styles different types of terms:
|
|
16
|
+
* - Local terms (defined with [[def:term]]) - get 'term-local' class
|
|
17
|
+
* - External terms (referenced with [[tref:spec,term]]) - get 'term-external' class
|
|
18
|
+
* - Regular terms (no special class)
|
|
19
|
+
*
|
|
20
|
+
* 3. QUALITY CONTROL: Handles problematic definition list structures:
|
|
21
|
+
* - Empty <dt> elements (removes them entirely)
|
|
22
|
+
* - Proper class assignment to avoid conflicts
|
|
23
|
+
*
|
|
24
|
+
* 4. SECTION DETECTION: Uses markers to identify terminology sections and apply
|
|
25
|
+
* appropriate styling only where needed.
|
|
26
|
+
*
|
|
27
|
+
* This module is central to the spec-up system's terminology management capabilities.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Applies definition list enhancements to a markdown-it instance
|
|
32
|
+
*
|
|
33
|
+
* @param {Object} md - The markdown-it instance to enhance
|
|
34
|
+
*
|
|
35
|
+
* This function sets up custom renderers for definition list elements (dl_open, dt_open, dt_close)
|
|
36
|
+
* that provide intelligent classification and styling based on content analysis.
|
|
37
|
+
*/
|
|
38
|
+
function applyDefinitionListEnhancements(md) {
|
|
39
|
+
|
|
40
|
+
// Store original renderers for fallback behavior
|
|
41
|
+
const originalDlRender = md.renderer.rules.dl_open || function (tokens, idx, options, env, self) {
|
|
42
|
+
return self.renderToken(tokens, idx, options);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const originalDtRender = md.renderer.rules.dt_open || function (tokens, idx, options, env, self) {
|
|
46
|
+
return self.renderToken(tokens, idx, options);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const originalDtCloseRender = md.renderer.rules.dt_close || function (tokens, idx, options, env, self) {
|
|
50
|
+
return self.renderToken(tokens, idx, options);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// State tracking: ensures we only add the terminology class once per document
|
|
54
|
+
let classAdded = false;
|
|
55
|
+
|
|
56
|
+
// ===================================================================================
|
|
57
|
+
// HELPER FUNCTIONS FOR TOKEN ANALYSIS
|
|
58
|
+
// ===================================================================================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Locates a specific HTML marker in the token stream
|
|
62
|
+
*
|
|
63
|
+
* This is used to find the "terminology-section-start" marker that indicates
|
|
64
|
+
* where terminology definitions begin in the document. Only definition lists
|
|
65
|
+
* that appear after this marker should be styled as terminology lists.
|
|
66
|
+
*
|
|
67
|
+
* @param {Array} tokens - The complete token array for the document
|
|
68
|
+
* @param {String} targetHtml - The HTML string to search for (e.g., 'terminology-section-start')
|
|
69
|
+
* @returns {Number} Index of the token containing the target HTML, or -1 if not found
|
|
70
|
+
*/
|
|
71
|
+
function findTargetIndex(tokens, targetHtml) {
|
|
72
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
73
|
+
if (tokens[i].content && tokens[i].content.includes(targetHtml)) {
|
|
74
|
+
return i;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return -1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Identifies and marks empty definition term elements for removal
|
|
82
|
+
*
|
|
83
|
+
* Empty <dt> elements (where dt_open is immediately followed by dt_close with no content)
|
|
84
|
+
* cause rendering and styling problems. This function marks them with an 'isEmpty' flag
|
|
85
|
+
* so they can be skipped during the rendering phase.
|
|
86
|
+
*
|
|
87
|
+
* @param {Array} tokens - The token array to analyze
|
|
88
|
+
* @param {Number} startIdx - Index to start searching from (typically after dl_open)
|
|
89
|
+
*/
|
|
90
|
+
function markEmptyDtElements(tokens, startIdx) {
|
|
91
|
+
for (let i = startIdx; i < tokens.length; i++) {
|
|
92
|
+
// Stop when we reach the end of this definition list
|
|
93
|
+
if (tokens[i].type === 'dl_close') {
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check for the empty dt pattern: dt_open immediately followed by dt_close
|
|
98
|
+
if (tokens[i].type === 'dt_open' &&
|
|
99
|
+
i + 1 < tokens.length &&
|
|
100
|
+
tokens[i + 1].type === 'dt_close') {
|
|
101
|
+
|
|
102
|
+
// Mark both tokens for removal during rendering
|
|
103
|
+
tokens[i].isEmpty = true;
|
|
104
|
+
tokens[i + 1].isEmpty = true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Placeholder for future last dd element processing
|
|
111
|
+
*
|
|
112
|
+
* This function was mentioned in the original code but not implemented.
|
|
113
|
+
* It could be used to identify the last <dd> in each dt/dd group for special styling.
|
|
114
|
+
*
|
|
115
|
+
* @param {Array} tokens - The token array to process
|
|
116
|
+
* @param {Number} startIdx - Index to start processing from
|
|
117
|
+
*/
|
|
118
|
+
function processLastDdElements(tokens, startIdx) {
|
|
119
|
+
let lastDdIndex = -1; // Tracks the most recent dd_open token
|
|
120
|
+
// TODO: Implement if needed for future enhancements
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ===================================================================================
|
|
124
|
+
// SPEC REFERENCE DETECTION FUNCTIONS
|
|
125
|
+
// ===================================================================================
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Determines if a definition list contains specification references
|
|
129
|
+
*
|
|
130
|
+
* Specification references are identified by dt elements with id attributes
|
|
131
|
+
* starting with "ref:" (e.g., id="ref:RFC2119"). These should NOT be styled
|
|
132
|
+
* as terminology lists since they serve a different purpose (bibliography).
|
|
133
|
+
*
|
|
134
|
+
* @param {Array} tokens - Token array to search through
|
|
135
|
+
* @param {Number} startIdx - Index to start searching from (after dl_open)
|
|
136
|
+
* @returns {Boolean} True if the dl contains spec references, false otherwise
|
|
137
|
+
*/
|
|
138
|
+
function containsSpecReferences(tokens, startIdx) {
|
|
139
|
+
for (let i = startIdx; i < tokens.length; i++) {
|
|
140
|
+
if (tokens[i].type === 'dl_close') {
|
|
141
|
+
break; // End of this definition list
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Check all three ways spec references can appear
|
|
145
|
+
if (isDtRef(tokens[i]) || isHtmlRef(tokens[i]) || isInlineRef(tokens[i])) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Checks if a dt_open token has a spec reference id attribute
|
|
154
|
+
*
|
|
155
|
+
* @param {Object} token - The token to check
|
|
156
|
+
* @returns {Boolean} True if token has id starting with "ref:"
|
|
157
|
+
*/
|
|
158
|
+
function isDtRef(token) {
|
|
159
|
+
if (token.type !== 'dt_open' || !token.attrs) return false;
|
|
160
|
+
return token.attrs.some(attr => attr[0] === 'id' && attr[1].startsWith('ref:'));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Checks if an HTML token contains a spec reference id
|
|
165
|
+
*
|
|
166
|
+
* @param {Object} token - The token to check
|
|
167
|
+
* @returns {Boolean} True if HTML content contains id="ref:..."
|
|
168
|
+
*/
|
|
169
|
+
function isHtmlRef(token) {
|
|
170
|
+
if (token.type !== 'html_block' && token.type !== 'html_inline') return false;
|
|
171
|
+
return token.content && token.content.includes('id="ref:');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Checks if an inline token contains a spec reference id
|
|
176
|
+
*
|
|
177
|
+
* @param {Object} token - The token to check
|
|
178
|
+
* @returns {Boolean} True if inline content contains id="ref:..."
|
|
179
|
+
*/
|
|
180
|
+
function isInlineRef(token) {
|
|
181
|
+
if (token.type !== 'inline') return false;
|
|
182
|
+
return token.content && token.content.includes('id="ref:');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ===================================================================================
|
|
186
|
+
// TERM TYPE DETECTION FUNCTIONS
|
|
187
|
+
// ===================================================================================
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Determines if a definition term is transcluded from an external source
|
|
191
|
+
*
|
|
192
|
+
* Transcluded terms are created using [[tref:external-spec,term]] syntax.
|
|
193
|
+
* These terms are defined in other specifications and referenced here.
|
|
194
|
+
* They get the 'term-external' CSS class for distinctive styling.
|
|
195
|
+
*
|
|
196
|
+
* @param {Array} tokens - Token array to analyze
|
|
197
|
+
* @param {Number} dtOpenIndex - Index of the dt_open token to check
|
|
198
|
+
* @returns {Boolean} True if the term is transcluded (external), false otherwise
|
|
199
|
+
*/
|
|
200
|
+
function isTermTranscluded(tokens, dtOpenIndex) {
|
|
201
|
+
// Search within this definition term only
|
|
202
|
+
for (let i = dtOpenIndex + 1; i < tokens.length; i++) {
|
|
203
|
+
if (tokens[i].type === 'dt_close') {
|
|
204
|
+
break; // End of this definition term
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Look for inline content with template tokens
|
|
208
|
+
if (tokens[i].type === 'inline' && tokens[i].children) {
|
|
209
|
+
for (let child of tokens[i].children) {
|
|
210
|
+
// Check if this is a tref (transcluded reference) template
|
|
211
|
+
if (child.type === 'template' &&
|
|
212
|
+
child.info &&
|
|
213
|
+
child.info.type === 'tref') {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Determines if a definition term is a local term definition
|
|
224
|
+
*
|
|
225
|
+
* Local terms are created using [[def:term,alias]] syntax.
|
|
226
|
+
* These are terms defined within the current specification.
|
|
227
|
+
* They get the 'term-local' CSS class for distinctive styling.
|
|
228
|
+
*
|
|
229
|
+
* @param {Array} tokens - Token array to analyze
|
|
230
|
+
* @param {Number} dtOpenIndex - Index of the dt_open token to check
|
|
231
|
+
* @returns {Boolean} True if the term is a local definition, false otherwise
|
|
232
|
+
*/
|
|
233
|
+
function isLocalTerm(tokens, dtOpenIndex) {
|
|
234
|
+
// Search within this definition term only
|
|
235
|
+
for (let i = dtOpenIndex + 1; i < tokens.length; i++) {
|
|
236
|
+
if (tokens[i].type === 'dt_close') {
|
|
237
|
+
break; // End of this definition term
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Look for inline content with template tokens
|
|
241
|
+
if (tokens[i].type === 'inline' && tokens[i].children) {
|
|
242
|
+
for (let child of tokens[i].children) {
|
|
243
|
+
// Check if this is a def (definition) template
|
|
244
|
+
if (child.type === 'template' &&
|
|
245
|
+
child.info &&
|
|
246
|
+
child.info.type === 'def') {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ===================================================================================
|
|
256
|
+
// CUSTOM RENDERERS
|
|
257
|
+
// ===================================================================================
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Custom renderer for definition list opening tags (<dl>)
|
|
261
|
+
*
|
|
262
|
+
* This renderer implements intelligent classification of definition lists:
|
|
263
|
+
*
|
|
264
|
+
* 1. Finds the terminology section marker in the document
|
|
265
|
+
* 2. Checks if this dl already has styling (to avoid conflicts)
|
|
266
|
+
* 3. Determines if this dl contains spec references (bibliography vs terminology)
|
|
267
|
+
* 4. Adds 'terms-and-definitions-list' class only to appropriate terminology lists
|
|
268
|
+
* 5. Processes empty dt elements and last dd elements
|
|
269
|
+
*
|
|
270
|
+
* @param {Array} tokens - Complete token array
|
|
271
|
+
* @param {Number} idx - Index of current dl_open token
|
|
272
|
+
* @param {Object} options - Markdown-it options
|
|
273
|
+
* @param {Object} env - Environment/context object
|
|
274
|
+
* @param {Object} self - Renderer instance
|
|
275
|
+
* @returns {String} HTML for the opening <dl> tag
|
|
276
|
+
*/
|
|
277
|
+
md.renderer.rules.dl_open = function (tokens, idx, options, env, self) {
|
|
278
|
+
const targetHtml = 'terminology-section-start';
|
|
279
|
+
let targetIndex = findTargetIndex(tokens, targetHtml);
|
|
280
|
+
|
|
281
|
+
// Check if this dl already has a class attribute (e.g., 'reference-list')
|
|
282
|
+
const existingClassIndex = tokens[idx].attrIndex('class');
|
|
283
|
+
const hasExistingClass = existingClassIndex >= 0;
|
|
284
|
+
|
|
285
|
+
// Check if this dl contains specification references
|
|
286
|
+
const hasSpecReferences = containsSpecReferences(tokens, idx + 1);
|
|
287
|
+
|
|
288
|
+
// Apply terminology list styling only if ALL conditions are met:
|
|
289
|
+
// 1. We found the terminology section marker
|
|
290
|
+
// 2. This dl appears after the marker
|
|
291
|
+
// 3. We haven't already added the class to a previous dl
|
|
292
|
+
// 4. This dl doesn't already have a class (preserves reference-list, etc.)
|
|
293
|
+
// 5. This dl doesn't contain spec references (avoids bibliography confusion)
|
|
294
|
+
if (targetIndex !== -1 &&
|
|
295
|
+
idx > targetIndex &&
|
|
296
|
+
!classAdded &&
|
|
297
|
+
!hasExistingClass &&
|
|
298
|
+
!hasSpecReferences) {
|
|
299
|
+
tokens[idx].attrPush(['class', 'terms-and-definitions-list']);
|
|
300
|
+
classAdded = true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Pre-process this definition list to handle problematic structures
|
|
304
|
+
markEmptyDtElements(tokens, idx + 1);
|
|
305
|
+
processLastDdElements(tokens, idx + 1);
|
|
306
|
+
|
|
307
|
+
return originalDlRender(tokens, idx, options, env, self);
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Custom renderer for definition term opening tags (<dt>)
|
|
312
|
+
*
|
|
313
|
+
* This renderer handles:
|
|
314
|
+
* 1. Skipping empty dt elements (marked during dl_open processing)
|
|
315
|
+
* 2. Adding 'term-external' class to transcluded terms (from [[tref:...]])
|
|
316
|
+
* 3. Adding 'term-local' class to local definitions (from [[def:...]])
|
|
317
|
+
* 4. Leaving regular terms without special classes
|
|
318
|
+
*
|
|
319
|
+
* @param {Array} tokens - Complete token array
|
|
320
|
+
* @param {Number} idx - Index of current dt_open token
|
|
321
|
+
* @param {Object} options - Markdown-it options
|
|
322
|
+
* @param {Object} env - Environment/context object
|
|
323
|
+
* @param {Object} self - Renderer instance
|
|
324
|
+
* @returns {String} HTML for the opening <dt> tag, or empty string if skipped
|
|
325
|
+
*/
|
|
326
|
+
md.renderer.rules.dt_open = function (tokens, idx, options, env, self) {
|
|
327
|
+
// Skip rendering empty dt elements that were marked during preprocessing
|
|
328
|
+
if (tokens[idx].isEmpty) {
|
|
329
|
+
return '';
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Look for the most recent file comment before this dt element
|
|
333
|
+
let sourceFile = null;
|
|
334
|
+
|
|
335
|
+
// Search backwards through all tokens to find the most recent HTML comment with file info
|
|
336
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
337
|
+
if (tokens[i].type === 'html_block' && tokens[i].content) {
|
|
338
|
+
const fileMatch = tokens[i].content.match(htmlComments.fileTracker);
|
|
339
|
+
if (fileMatch) {
|
|
340
|
+
sourceFile = fileMatch[1];
|
|
341
|
+
break; // Use the most recent file comment
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Add data-sourcefile attribute to the dt element if source file was found
|
|
347
|
+
if (sourceFile) {
|
|
348
|
+
tokens[idx].attrPush(['data-sourcefile', sourceFile]);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Determine term type and add appropriate CSS class
|
|
352
|
+
if (isTermTranscluded(tokens, idx)) {
|
|
353
|
+
// External/transcluded term - add or append 'term-external' class
|
|
354
|
+
const classIndex = tokens[idx].attrIndex('class');
|
|
355
|
+
if (classIndex < 0) {
|
|
356
|
+
tokens[idx].attrPush(['class', 'term-external']);
|
|
357
|
+
} else {
|
|
358
|
+
tokens[idx].attrs[classIndex][1] += ' term-external';
|
|
359
|
+
}
|
|
360
|
+
} else if (isLocalTerm(tokens, idx)) {
|
|
361
|
+
// Local definition - add or append 'term-local' class
|
|
362
|
+
const classIndex = tokens[idx].attrIndex('class');
|
|
363
|
+
if (classIndex < 0) {
|
|
364
|
+
tokens[idx].attrPush(['class', 'term-local']);
|
|
365
|
+
} else {
|
|
366
|
+
tokens[idx].attrs[classIndex][1] += ' term-local';
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// Regular terms get no special class
|
|
370
|
+
|
|
371
|
+
return originalDtRender(tokens, idx, options, env, self);
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Custom renderer for definition term closing tags (</dt>)
|
|
376
|
+
*
|
|
377
|
+
* This renderer ensures that empty dt elements are completely omitted
|
|
378
|
+
* from the final HTML output by skipping their closing tags as well.
|
|
379
|
+
*
|
|
380
|
+
* @param {Array} tokens - Complete token array
|
|
381
|
+
* @param {Number} idx - Index of current dt_close token
|
|
382
|
+
* @param {Object} options - Markdown-it options
|
|
383
|
+
* @param {Object} env - Environment/context object
|
|
384
|
+
* @param {Object} self - Renderer instance
|
|
385
|
+
* @returns {String} HTML for the closing </dt> tag, or empty string if skipped
|
|
386
|
+
*/
|
|
387
|
+
md.renderer.rules.dt_close = function (tokens, idx, options, env, self) {
|
|
388
|
+
// Skip rendering the closing tag for empty dt elements
|
|
389
|
+
// This completes the removal of problematic empty dt structures
|
|
390
|
+
if (tokens[idx].isEmpty) {
|
|
391
|
+
return '';
|
|
392
|
+
}
|
|
393
|
+
return originalDtCloseRender(tokens, idx, options, env, self);
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
module.exports = applyDefinitionListEnhancements;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Markdown-it Extensions Module Orchestrator
|
|
5
|
+
*
|
|
6
|
+
* This module serves as the main entry point for all markdown-it enhancements
|
|
7
|
+
* used in the spec-up system. It provides a clean interface to apply all
|
|
8
|
+
* custom rendering rules and functionality to a markdown-it instance.
|
|
9
|
+
*
|
|
10
|
+
* The module is organized into focused sub-modules, each handling a specific
|
|
11
|
+
* aspect of markdown processing:
|
|
12
|
+
*
|
|
13
|
+
* - TABLE ENHANCEMENT: Bootstrap styling and responsive wrappers
|
|
14
|
+
* - TEMPLATE-TAG SYNTAX: Custom [[template-tag:args]] syntax processing
|
|
15
|
+
* - LINK ENHANCEMENT: Path-based attributes for links
|
|
16
|
+
* - DEFINITION LISTS: Advanced terminology and reference list handling
|
|
17
|
+
*
|
|
18
|
+
* This modular approach makes the code more maintainable and easier to
|
|
19
|
+
* understand for developers unfamiliar with the markdown-it library.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// Import all the specialized enhancement modules
|
|
23
|
+
const applyTableEnhancements = require('./table-enhancement');
|
|
24
|
+
const applyTemplateTagSyntax = require('./template-tag-syntax');
|
|
25
|
+
const applyLinkEnhancements = require('./link-enhancement');
|
|
26
|
+
const applyDefinitionListEnhancements = require('./definition-lists');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Applies all markdown-it enhancements to a markdown-it instance
|
|
30
|
+
*
|
|
31
|
+
* This is the main function that consuming code should call. It orchestrates
|
|
32
|
+
* the application of all enhancement modules in the correct order.
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} md - The markdown-it instance to enhance
|
|
35
|
+
* @param {Array} templates - Array of template-tag handler objects for custom syntax
|
|
36
|
+
* Each template-tag handler should have:
|
|
37
|
+
* - filter(type): function returning true if handler processes this type
|
|
38
|
+
* - parse(token, type, ...args): optional preprocessing function
|
|
39
|
+
* - render(token, type, ...args): function returning HTML string
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* const MarkdownIt = require('markdown-it');
|
|
43
|
+
* const applyMarkdownItExtensions = require('./markdown-it');
|
|
44
|
+
*
|
|
45
|
+
* const md = new MarkdownIt();
|
|
46
|
+
* const templates = [
|
|
47
|
+
* {
|
|
48
|
+
* filter: type => type === 'def',
|
|
49
|
+
* render: (token, type, term) => `<span id="term:${term}">${term}</span>`
|
|
50
|
+
* }
|
|
51
|
+
* ];
|
|
52
|
+
*
|
|
53
|
+
* applyMarkdownItExtensions(md, templates);
|
|
54
|
+
* const html = md.render('[[def:example-term]]');
|
|
55
|
+
*/
|
|
56
|
+
function applyMarkdownItExtensions(md, templates = []) {
|
|
57
|
+
|
|
58
|
+
// Apply enhancements in order of dependency
|
|
59
|
+
// Some modules may depend on others being applied first
|
|
60
|
+
|
|
61
|
+
// 1. Table enhancements - independent, can be applied first
|
|
62
|
+
applyTableEnhancements(md);
|
|
63
|
+
|
|
64
|
+
// 2. Template-tag syntax - should be applied early as other modules may depend on it
|
|
65
|
+
applyTemplateTagSyntax(md, templates);
|
|
66
|
+
|
|
67
|
+
// 3. Link enhancements - independent, can be applied anytime
|
|
68
|
+
applyLinkEnhancements(md);
|
|
69
|
+
|
|
70
|
+
// 4. Definition lists - depends on template-tag syntax for term type detection
|
|
71
|
+
applyDefinitionListEnhancements(md);
|
|
72
|
+
|
|
73
|
+
// The markdown-it instance is now fully enhanced and ready for use
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Export the main orchestrator function
|
|
77
|
+
module.exports = applyMarkdownItExtensions;
|
|
78
|
+
|
|
79
|
+
// Also export individual modules for fine-grained control if needed
|
|
80
|
+
module.exports.tableEnhancements = applyTableEnhancements;
|
|
81
|
+
module.exports.templateTagSyntax = applyTemplateTagSyntax;
|
|
82
|
+
module.exports.linkEnhancements = applyLinkEnhancements;
|
|
83
|
+
module.exports.definitionLists = applyDefinitionListEnhancements;
|