spec-up-t 1.3.1 → 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 +17 -11
- package/assets/compiled/head.css +6 -4
- package/assets/css/collapse-definitions.css +0 -1
- 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/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 +1 -1
- 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/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 +24 -16
- 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/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 +1 -1
- package/src/install-from-boilerplate/boilerplate/specs.json +2 -1
- package/src/install-from-boilerplate/config-scripts-keys.js +3 -3
- 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/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/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
|
@@ -12,13 +12,14 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @requires fs-extra - File system operations with extra methods.
|
|
14
14
|
* @requires path - Utilities for working with file and directory paths.
|
|
15
|
-
* @file src/create-term-index.js
|
|
15
|
+
* @file src/pipeline/configuration/create-term-index.js
|
|
16
16
|
* @author Kor Dwarshuis
|
|
17
17
|
* @version 1.1.0
|
|
18
18
|
* @since 2024-09-02
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
const { shouldProcessFile } = require('
|
|
21
|
+
const { shouldProcessFile } = require('../../utils/file-filter.js');
|
|
22
|
+
const Logger = require('../../utils/logger.js');
|
|
22
23
|
|
|
23
24
|
function createTermIndex() {
|
|
24
25
|
try {
|
|
@@ -28,41 +29,41 @@ function createTermIndex() {
|
|
|
28
29
|
|
|
29
30
|
// Check if specs.json exists
|
|
30
31
|
if (!fs.existsSync(configPath)) {
|
|
31
|
-
|
|
32
|
+
Logger.warn(`Config file '${configPath}' not found. Using default configuration.`);
|
|
32
33
|
var config = { specs: [] };
|
|
33
34
|
} else {
|
|
34
35
|
// Read config with try-catch to handle parsing errors
|
|
35
36
|
try {
|
|
36
37
|
var config = fs.readJsonSync(configPath);
|
|
37
38
|
} catch (readError) {
|
|
38
|
-
|
|
39
|
+
Logger.warn(`Error reading config file: ${readError.message}. Using default configuration.`);
|
|
39
40
|
var config = { specs: [] };
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
// Provide defaults for missing config
|
|
44
45
|
if (!config) {
|
|
45
|
-
|
|
46
|
+
Logger.warn('Config file is empty or invalid. Using defaults.');
|
|
46
47
|
config = { specs: [] };
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
if (!config.specs) {
|
|
50
|
-
|
|
51
|
+
Logger.warn('No specs array found in config. Creating empty specs array.');
|
|
51
52
|
config.specs = [];
|
|
52
53
|
} else if (!Array.isArray(config.specs)) {
|
|
53
|
-
|
|
54
|
+
Logger.warn('Config specs is not an array. Converting to array.');
|
|
54
55
|
config.specs = [config.specs]; // Convert to array if it's an object
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
// If no valid specs, create an empty term index
|
|
58
59
|
if (config.specs.length === 0) {
|
|
59
|
-
|
|
60
|
+
Logger.warn('No specs found in configuration. Creating an empty term index.');
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
// Extract spec directories with fallback to current directory
|
|
63
64
|
const specDirectories = config.specs.map((spec, index) => {
|
|
64
65
|
if (!spec.spec_directory) {
|
|
65
|
-
|
|
66
|
+
Logger.warn(`spec_directory missing in specs.json entry #${index + 1}. Using current directory.`);
|
|
66
67
|
return '.'; // Default to current directory
|
|
67
68
|
}
|
|
68
69
|
return spec.spec_directory;
|
|
@@ -71,7 +72,7 @@ function createTermIndex() {
|
|
|
71
72
|
// Extract term directories with fallback to default value
|
|
72
73
|
const specTermDirectoryName = config.specs.map((spec, index) => {
|
|
73
74
|
if (!spec.spec_terms_directory) {
|
|
74
|
-
|
|
75
|
+
Logger.warn(`spec_terms_directory missing in specs.json entry #${index + 1}. Using default 'terms' directory.`);
|
|
75
76
|
return 'terms'; // Default directory name for terms
|
|
76
77
|
}
|
|
77
78
|
return spec.spec_terms_directory;
|
|
@@ -79,7 +80,7 @@ function createTermIndex() {
|
|
|
79
80
|
|
|
80
81
|
// Safety check - if we have no valid entries, warn and exit cleanly
|
|
81
82
|
if (specDirectories.length === 0 || specTermDirectoryName.length === 0) {
|
|
82
|
-
|
|
83
|
+
Logger.info('No term directories found in configuration. Creating empty term index.');
|
|
83
84
|
|
|
84
85
|
// Create an empty term index
|
|
85
86
|
const outputPathJSON = path.join('.cache', 'term-index.json');
|
|
@@ -87,14 +88,14 @@ function createTermIndex() {
|
|
|
87
88
|
fs.mkdirSync('.cache', { recursive: true });
|
|
88
89
|
}
|
|
89
90
|
fs.writeJsonSync(outputPathJSON, [], { spaces: 2 });
|
|
90
|
-
|
|
91
|
+
Logger.success(`Empty term index created at: ${outputPathJSON}`);
|
|
91
92
|
return; // Exit function early
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
// Verify that the base spec directory exists
|
|
95
96
|
const baseSpecDir = specDirectories[0];
|
|
96
97
|
if (!baseSpecDir || !fs.existsSync(baseSpecDir)) {
|
|
97
|
-
|
|
98
|
+
Logger.warn(`Spec directory '${baseSpecDir}' does not exist. Creating empty term index.`);
|
|
98
99
|
|
|
99
100
|
// Create an empty term index
|
|
100
101
|
const outputPathJSON = path.join('.cache', 'term-index.json');
|
|
@@ -102,7 +103,7 @@ function createTermIndex() {
|
|
|
102
103
|
fs.mkdirSync('.cache', { recursive: true });
|
|
103
104
|
}
|
|
104
105
|
fs.writeJsonSync(outputPathJSON, [], { spaces: 2 });
|
|
105
|
-
|
|
106
|
+
Logger.success(`Empty term index created at: ${outputPathJSON}`);
|
|
106
107
|
return; // Exit function early
|
|
107
108
|
}
|
|
108
109
|
|
|
@@ -111,14 +112,14 @@ function createTermIndex() {
|
|
|
111
112
|
|
|
112
113
|
let files = [];
|
|
113
114
|
if (!fs.existsSync(termsDir)) {
|
|
114
|
-
|
|
115
|
+
Logger.warn(`Terms directory '${termsDir}' does not exist. Creating an empty term index.`);
|
|
115
116
|
} else {
|
|
116
117
|
// Get list of files and filter them
|
|
117
118
|
files = fs.readdirSync(termsDir).filter(shouldProcessFile);
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
if (files.length === 0) {
|
|
121
|
-
|
|
122
|
+
Logger.warn('No term files found to process.');
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
const filePaths = files.map(file => specTermDirectoryName[0] + '/' + file);
|
|
@@ -132,12 +133,12 @@ function createTermIndex() {
|
|
|
132
133
|
// Write the term index file
|
|
133
134
|
try {
|
|
134
135
|
fs.writeJsonSync(outputPathJSON, filePaths, { spaces: 2 });
|
|
135
|
-
|
|
136
|
+
Logger.success(`Term index created with ${files.length} terms. Output: ${outputPathJSON}`);
|
|
136
137
|
} catch (writeError) {
|
|
137
138
|
throw new Error(`Failed to write term index file: ${writeError.message}`);
|
|
138
139
|
}
|
|
139
140
|
} catch (error) {
|
|
140
|
-
|
|
141
|
+
Logger.error(`Error creating term index: ${error.message}`);
|
|
141
142
|
throw error;
|
|
142
143
|
}
|
|
143
144
|
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
const fs = require('fs-extra');
|
|
16
16
|
const path = require('path');
|
|
17
|
+
const Logger = require('../../utils/logger.js');
|
|
17
18
|
|
|
18
19
|
function createVersionsIndex(outputPath) {
|
|
19
20
|
// Directory containing the version files
|
|
@@ -22,7 +23,7 @@ function createVersionsIndex(outputPath) {
|
|
|
22
23
|
// Check if the directory that holds the versions / snapshots exists, if not create it
|
|
23
24
|
if (!fs.existsSync(versionsDir)) {
|
|
24
25
|
fs.mkdirSync(versionsDir, { recursive: true });
|
|
25
|
-
|
|
26
|
+
Logger.info('Directory created:', versionsDir);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
// Get all directories in the destination directory
|
|
@@ -71,9 +72,9 @@ function createVersionsIndex(outputPath) {
|
|
|
71
72
|
const indexPath = path.join(versionsDir, 'index.html');
|
|
72
73
|
fs.writeFile(indexPath, htmlContent, (err) => {
|
|
73
74
|
if (err) {
|
|
74
|
-
|
|
75
|
+
Logger.error(`Error writing index file: ${err}`);
|
|
75
76
|
} else {
|
|
76
|
-
|
|
77
|
+
Logger.success(`Index file created at ${indexPath}`);
|
|
77
78
|
}
|
|
78
79
|
});
|
|
79
80
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @function
|
|
10
10
|
* @name insertTermIndex
|
|
11
11
|
* @returns {void}
|
|
12
|
-
* @file src/insert-term-index.js
|
|
12
|
+
* @file src/pipeline/configuration/insert-term-index.js
|
|
13
13
|
* @author Kor Dwarshuis
|
|
14
14
|
* @version 1.0.0
|
|
15
15
|
* @since 2024-09-02
|
|
@@ -26,7 +26,7 @@ function insertTermIndex() {
|
|
|
26
26
|
|
|
27
27
|
// Find the index of the "terms-and-definitions-intro.md" file in the markdown paths
|
|
28
28
|
const index = markdownPaths.indexOf('terms-and-definitions-intro.md');
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
//
|
|
31
31
|
if (index !== -1) {
|
|
32
32
|
// Insert the items of the "terms" array after the found index
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles configuration and initialization tasks before rendering specs.
|
|
3
|
+
* This module centralizes setup logic to reduce complexity in index.js.
|
|
4
|
+
* It loads config, runs validators, prepares external specs, and initializes shared variables.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const findPkgDir = require('find-pkg-dir');
|
|
10
|
+
|
|
11
|
+
const { initialize } = require('../../init.js');
|
|
12
|
+
const Logger = require('../../utils/logger.js');
|
|
13
|
+
const { runJsonKeyValidatorSync } = require('../../json-key-validator.js');
|
|
14
|
+
const { createTermIndex } = require('./create-term-index.js');
|
|
15
|
+
const { insertTermIndex } = require('./insert-term-index.js');
|
|
16
|
+
const { normalizeTerminologyMarkdown } = require('../preprocessing/normalize-terminology-markdown.js');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Initializes configuration and shared variables for spec processing.
|
|
20
|
+
* @param {Object} options - Options passed to the main function.
|
|
21
|
+
* @returns {Object} An object containing config, externalSpecsList, template, assets, and other shared variables.
|
|
22
|
+
*/
|
|
23
|
+
async function initializeConfig(options = {}) {
|
|
24
|
+
try {
|
|
25
|
+
await initialize();
|
|
26
|
+
|
|
27
|
+
runJsonKeyValidatorSync();
|
|
28
|
+
createTermIndex();
|
|
29
|
+
insertTermIndex();
|
|
30
|
+
|
|
31
|
+
const modulePath = findPkgDir(__dirname);
|
|
32
|
+
let config = fs.readJsonSync('./.cache/specs-generated.json');
|
|
33
|
+
|
|
34
|
+
const createExternalSpecsList = require('./create-external-specs-list.js');
|
|
35
|
+
const externalSpecsList = createExternalSpecsList(config);
|
|
36
|
+
|
|
37
|
+
const createVersionsIndex = require('./create-versions-index.js');
|
|
38
|
+
createVersionsIndex(config.specs[0].output_path);
|
|
39
|
+
|
|
40
|
+
normalizeTerminologyMarkdown(path.join(config.specs[0].spec_directory, config.specs[0].spec_terms_directory));
|
|
41
|
+
|
|
42
|
+
let template = fs.readFileSync(path.join(modulePath, 'templates/template.html'), 'utf8');
|
|
43
|
+
let assets = fs.readJsonSync(modulePath + '/config/asset-map.json');
|
|
44
|
+
|
|
45
|
+
// Initialize shared variables
|
|
46
|
+
let externalReferences;
|
|
47
|
+
let references = [];
|
|
48
|
+
let definitions = [];
|
|
49
|
+
let toc;
|
|
50
|
+
let specGroups = {};
|
|
51
|
+
let noticeTitles = {};
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
config,
|
|
55
|
+
externalSpecsList,
|
|
56
|
+
template,
|
|
57
|
+
assets,
|
|
58
|
+
externalReferences,
|
|
59
|
+
references,
|
|
60
|
+
definitions,
|
|
61
|
+
specGroups,
|
|
62
|
+
noticeTitles
|
|
63
|
+
};
|
|
64
|
+
} catch (error) {
|
|
65
|
+
Logger.error(`Error during configuration initialization: ${error.message}`);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { initializeConfig };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Markdown-it Extensions - Legacy Interface
|
|
5
|
+
*
|
|
6
|
+
* This file provides backward compatibility for the refactored markdown-it extensions.
|
|
7
|
+
* All the complex logic has been moved to specialized modules in the './markdown-it/' directory
|
|
8
|
+
* for better maintainability and understanding.
|
|
9
|
+
*
|
|
10
|
+
* The modular approach breaks down the functionality into:
|
|
11
|
+
* - Table enhancements (Bootstrap styling, responsive wrappers)
|
|
12
|
+
* - Template-tag syntax processing ([[def:term]], [[tref:spec,term]], etc.)
|
|
13
|
+
* - Link enhancements (path-based attributes)
|
|
14
|
+
* - Definition list processing (terminology vs references, term classification)
|
|
15
|
+
*
|
|
16
|
+
* This refactoring reduces cognitive complexity and makes the code more approachable
|
|
17
|
+
* for developers who are not familiar with the markdown-it library.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Import the new modular markdown-it extensions
|
|
21
|
+
const applyMarkdownItExtensions = require('../../markdown-it');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Legacy interface function that maintains compatibility with existing code
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} md - The markdown-it instance to enhance
|
|
27
|
+
* @param {Array} templates - Array of template-tag handler objects for custom syntax
|
|
28
|
+
*
|
|
29
|
+
* This function simply delegates to the new modular system while maintaining
|
|
30
|
+
* the same interface that consuming code expects.
|
|
31
|
+
*/
|
|
32
|
+
module.exports = function (md, templates = []) {
|
|
33
|
+
// Apply all markdown-it enhancements using the new modular system
|
|
34
|
+
applyMarkdownItExtensions(md, templates);
|
|
35
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configures and exports a fully set up markdown-it instance.
|
|
3
|
+
* This module integrates custom extensions, plugins, and related constants.
|
|
4
|
+
* It centralizes markdown parsing setup to reduce complexity in index.js.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const MarkdownIt = require('markdown-it');
|
|
8
|
+
const containers = require('markdown-it-container');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs-extra');
|
|
11
|
+
const findPkgDir = require('find-pkg-dir');
|
|
12
|
+
|
|
13
|
+
const { configurePlugins } = require('../../markdown-it/plugins');
|
|
14
|
+
const { createTemplateTagParser, createSpecParser } = require('../../parsers');
|
|
15
|
+
const { whitespace, templateTags } = require('../../utils/regex-patterns.js');
|
|
16
|
+
|
|
17
|
+
// Constants used in markdown parsing
|
|
18
|
+
const noticeTypes = {
|
|
19
|
+
note: 1,
|
|
20
|
+
issue: 1,
|
|
21
|
+
example: 1,
|
|
22
|
+
warning: 1,
|
|
23
|
+
todo: 1
|
|
24
|
+
};
|
|
25
|
+
// Domain-specific regex patterns for markdown parsing (now centralized)
|
|
26
|
+
const specNameRegex = templateTags.specName;
|
|
27
|
+
const templateTagRegex = templateTags.terminology;
|
|
28
|
+
|
|
29
|
+
// Load spec corpus
|
|
30
|
+
const modulePath = findPkgDir(__dirname);
|
|
31
|
+
const specCorpus = fs.readJsonSync(path.join(modulePath, 'assets/compiled/refs.json'));
|
|
32
|
+
|
|
33
|
+
// Global variables (shared across renders)
|
|
34
|
+
let definitions = global.definitions;
|
|
35
|
+
let references = global.references;
|
|
36
|
+
let specGroups = global.specGroups;
|
|
37
|
+
let noticeTitles = global.noticeTitles;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates and configures a markdown-it instance with extensions and plugins.
|
|
41
|
+
* @param {Object} config - Configuration object (e.g., for anchor symbol).
|
|
42
|
+
* @param {Function} setToc - Function to set the table of contents HTML.
|
|
43
|
+
* @returns {Object} The configured markdown-it instance.
|
|
44
|
+
*/
|
|
45
|
+
function createMarkdownParser(config, setToc) {
|
|
46
|
+
// Create parser functions with bound dependencies - cleaner than classes
|
|
47
|
+
const templateTagParser = createTemplateTagParser(config, global);
|
|
48
|
+
const specParser = createSpecParser(specCorpus, global);
|
|
49
|
+
|
|
50
|
+
let md = MarkdownIt({
|
|
51
|
+
html: true,
|
|
52
|
+
linkify: true,
|
|
53
|
+
typographer: true
|
|
54
|
+
})
|
|
55
|
+
.use(require('./apply-markdown-it-extensions.js'), [
|
|
56
|
+
/*
|
|
57
|
+
The first extension focuses on template-tag constructs.
|
|
58
|
+
All complex logic is now delegated to pure functions.
|
|
59
|
+
*/
|
|
60
|
+
{
|
|
61
|
+
filter: type => type.match(templateTagRegex),
|
|
62
|
+
parse: (token, type, primary) => templateTagParser(token, type, primary)
|
|
63
|
+
},
|
|
64
|
+
/*
|
|
65
|
+
The second extension handles specification references.
|
|
66
|
+
All complex logic is now delegated to pure functions.
|
|
67
|
+
*/
|
|
68
|
+
{
|
|
69
|
+
filter: type => type.match(specNameRegex),
|
|
70
|
+
parse: (token, type, name) => specParser.parseSpecReference(token, type, name),
|
|
71
|
+
render: (token, type, name) => specParser.renderSpecReference(token, type, name)
|
|
72
|
+
}
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
md = configurePlugins(md, config, containers, noticeTypes, global.noticeTitles, setToc);
|
|
76
|
+
|
|
77
|
+
return md;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
createMarkdownParser,
|
|
82
|
+
noticeTypes,
|
|
83
|
+
spaceRegex: whitespace.oneOrMore,
|
|
84
|
+
specNameRegex,
|
|
85
|
+
templateTagRegex,
|
|
86
|
+
specCorpus,
|
|
87
|
+
definitions,
|
|
88
|
+
references,
|
|
89
|
+
specGroups,
|
|
90
|
+
noticeTitles,
|
|
91
|
+
// Export parsers for direct access if needed
|
|
92
|
+
createTemplateTagParser,
|
|
93
|
+
createSpecParser
|
|
94
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Parser Integration Tests - Functional Style
|
|
3
|
+
*
|
|
4
|
+
* These tests verify that the markdown parser integration works correctly
|
|
5
|
+
* and maintains backward compatibility while providing better testability.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
createMarkdownParser
|
|
10
|
+
} = require('./create-markdown-parser.js');
|
|
11
|
+
|
|
12
|
+
// Tests for integrating the functional parser system with markdown processing
|
|
13
|
+
describe('Markdown Parser Integration', () => {
|
|
14
|
+
let mockConfig;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
mockConfig = {
|
|
18
|
+
specs: [{
|
|
19
|
+
external_specs: [{
|
|
20
|
+
external_spec: 'test-spec',
|
|
21
|
+
gh_page: 'https://example.com/spec'
|
|
22
|
+
}]
|
|
23
|
+
}]
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Test: Can the system create a markdown parser using the functional approach?
|
|
28
|
+
test('should create parser with functional system', () => {
|
|
29
|
+
const mockSetToc = jest.fn();
|
|
30
|
+
const parser = createMarkdownParser(mockConfig, mockSetToc);
|
|
31
|
+
|
|
32
|
+
expect(parser).toBeDefined();
|
|
33
|
+
expect(parser.render).toBeDefined();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Test: Does the refactored system maintain compatibility with existing markdown processing?
|
|
37
|
+
test('should maintain backward compatibility', () => {
|
|
38
|
+
const mockSetToc = jest.fn();
|
|
39
|
+
const parser = createMarkdownParser(mockConfig, mockSetToc);
|
|
40
|
+
|
|
41
|
+
// Test basic markdown rendering still works
|
|
42
|
+
const basicMarkdown = '# Test Heading\n\nSome content.';
|
|
43
|
+
const result = parser.render(basicMarkdown);
|
|
44
|
+
|
|
45
|
+
expect(result).toContain('<h1');
|
|
46
|
+
expect(result).toContain('Test Heading');
|
|
47
|
+
expect(result).toContain('<p>Some content.</p>');
|
|
48
|
+
});
|
|
49
|
+
});
|
package/src/{html-dom-processor.js → pipeline/postprocessing/definition-list-postprocessor.js}
RENAMED
|
@@ -100,7 +100,10 @@ function fixDefinitionListStructure(html) {
|
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
// Find any transcluded term dt elements anywhere in the document
|
|
103
|
-
const transcludedTerms = document.querySelectorAll('dt.
|
|
103
|
+
const transcludedTerms = document.querySelectorAll('dt.term-external, dt.term-local');
|
|
104
|
+
|
|
105
|
+
// Also find any tref spans that are in paragraphs (standalone trefs)
|
|
106
|
+
const standaloneTrefSpans = document.querySelectorAll('p span.term-external');
|
|
104
107
|
|
|
105
108
|
let mainDl = null;
|
|
106
109
|
|
|
@@ -109,7 +112,7 @@ function fixDefinitionListStructure(html) {
|
|
|
109
112
|
mainDl = dlElements[0]; // Use the first one
|
|
110
113
|
}
|
|
111
114
|
// If we have transcluded terms but no main dl, we need to create one
|
|
112
|
-
else if (transcludedTerms.length > 0) {
|
|
115
|
+
else if (transcludedTerms.length > 0 || standaloneTrefSpans.length > 0) {
|
|
113
116
|
// Create a new dl element with the right class
|
|
114
117
|
mainDl = document.createElement('dl');
|
|
115
118
|
mainDl.className = 'terms-and-definitions-list';
|
|
@@ -125,10 +128,18 @@ function fixDefinitionListStructure(html) {
|
|
|
125
128
|
marker.parentNode.appendChild(mainDl);
|
|
126
129
|
}
|
|
127
130
|
} else {
|
|
128
|
-
// Fallback
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
// Fallback - insert before the first term we can find (dt or standalone span)
|
|
132
|
+
let firstTerm = transcludedTerms[0];
|
|
133
|
+
if (!firstTerm && standaloneTrefSpans.length > 0) {
|
|
134
|
+
firstTerm = standaloneTrefSpans[0].closest('p');
|
|
135
|
+
}
|
|
136
|
+
if (firstTerm) {
|
|
137
|
+
const insertPoint = firstTerm.parentNode;
|
|
138
|
+
insertPoint.parentNode.insertBefore(mainDl, insertPoint);
|
|
139
|
+
} else {
|
|
140
|
+
// Last resort - append to body
|
|
141
|
+
document.body.appendChild(mainDl);
|
|
142
|
+
}
|
|
132
143
|
}
|
|
133
144
|
}
|
|
134
145
|
|
|
@@ -160,6 +171,30 @@ function fixDefinitionListStructure(html) {
|
|
|
160
171
|
return group;
|
|
161
172
|
}
|
|
162
173
|
|
|
174
|
+
// First, process any standalone tref spans in paragraphs and convert them to dt elements
|
|
175
|
+
standaloneTrefSpans.forEach(trefSpan => {
|
|
176
|
+
const paragraph = trefSpan.closest('p');
|
|
177
|
+
if (paragraph) {
|
|
178
|
+
// Create a new dt element for this tref
|
|
179
|
+
const newDt = document.createElement('dt');
|
|
180
|
+
newDt.className = 'term-external';
|
|
181
|
+
|
|
182
|
+
// Move the tref span into the dt
|
|
183
|
+
newDt.appendChild(trefSpan.cloneNode(true));
|
|
184
|
+
|
|
185
|
+
// Create an empty dd element to satisfy definition list structure
|
|
186
|
+
const newDd = document.createElement('dd');
|
|
187
|
+
newDd.innerHTML = ''; // Truly empty, no hacks
|
|
188
|
+
|
|
189
|
+
// Add both to the main dl
|
|
190
|
+
mainDl.appendChild(newDt);
|
|
191
|
+
mainDl.appendChild(newDd);
|
|
192
|
+
|
|
193
|
+
// Remove the paragraph
|
|
194
|
+
paragraph.parentNode.removeChild(paragraph);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
163
198
|
// Process all transcluded terms and move them with their dd elements
|
|
164
199
|
transcludedTerms.forEach(dt => {
|
|
165
200
|
// Check if this dt is not already inside our main dl
|
|
@@ -269,10 +304,34 @@ function fixDefinitionListStructure(html) {
|
|
|
269
304
|
currentNode.parentNode.removeChild(currentNode);
|
|
270
305
|
}
|
|
271
306
|
}
|
|
272
|
-
else if (currentNode.tagName === 'P'
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
307
|
+
else if (currentNode.tagName === 'P') {
|
|
308
|
+
// Check if this paragraph contains a standalone tref term
|
|
309
|
+
const trefSpan = currentNode.querySelector('span.term-external');
|
|
310
|
+
if (trefSpan) {
|
|
311
|
+
// Create a new dt element for this tref
|
|
312
|
+
const newDt = document.createElement('dt');
|
|
313
|
+
newDt.className = 'term-external';
|
|
314
|
+
|
|
315
|
+
// Move the tref span into the dt
|
|
316
|
+
newDt.appendChild(trefSpan.cloneNode(true));
|
|
317
|
+
|
|
318
|
+
// Create an empty dd element to satisfy definition list structure
|
|
319
|
+
const newDd = document.createElement('dd');
|
|
320
|
+
newDd.innerHTML = ''; // Truly empty, no hacks
|
|
321
|
+
|
|
322
|
+
// Add both to the main dl
|
|
323
|
+
mainDl.appendChild(newDt);
|
|
324
|
+
mainDl.appendChild(newDd);
|
|
325
|
+
|
|
326
|
+
// Remove the paragraph
|
|
327
|
+
currentNode.parentNode.removeChild(currentNode);
|
|
328
|
+
}
|
|
329
|
+
else if ((!currentNode.textContent || currentNode.textContent.trim() === '') &&
|
|
330
|
+
currentNode.children.length === 0) {
|
|
331
|
+
// Remove truly empty paragraphs (no text and no child elements) - these break the list structure
|
|
332
|
+
// This prevents removal of paragraphs containing only images or other elements
|
|
333
|
+
currentNode.parentNode.removeChild(currentNode);
|
|
334
|
+
}
|
|
276
335
|
}
|
|
277
336
|
}
|
|
278
337
|
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* 3. Post-processing: Restore escaped sequences as literals
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
const { escaping } = require('../../utils/regex-patterns.js');
|
|
12
|
+
|
|
11
13
|
const ESCAPED_PLACEHOLDER = '__SPEC_UP_ESCAPED_TAG__';
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -40,7 +42,7 @@ function postProcessEscapes(text) {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
// Restore placeholders to literal [[
|
|
43
|
-
return text.replace(
|
|
45
|
+
return text.replace(escaping.placeholderRegex, '[[');
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
/**
|