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
package/src/configure.js
CHANGED
|
@@ -1,113 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* 4. Defines a set of questions to gather information from the user.
|
|
9
|
-
*
|
|
10
|
-
* @module configure
|
|
2
|
+
* Legacy entry point preserved for backwards compatibility with existing installations.
|
|
3
|
+
*
|
|
4
|
+
* The original interactive implementation now lives in
|
|
5
|
+
* `src/pipeline/configuration/configure-starterpack.js`. Requiring that module keeps the
|
|
6
|
+
* behaviour identical (including auto-run) while new code can import the functional helper
|
|
7
|
+
* directly from the pipeline path.
|
|
11
8
|
*/
|
|
12
9
|
|
|
13
|
-
const
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const readline = require('readline');
|
|
10
|
+
const configurator = require('./pipeline/configuration/configure-starterpack');
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
const JSON_FILE_PATH = path.resolve(process.cwd(), 'specs.json');
|
|
19
|
-
|
|
20
|
-
// Key for accessing specs in the JSON file
|
|
21
|
-
const SPECS_KEY = 'specs';
|
|
22
|
-
|
|
23
|
-
// Check if the JSON file exists
|
|
24
|
-
if (!fs.existsSync(JSON_FILE_PATH)) {
|
|
25
|
-
console.error(`Error: ${JSON_FILE_PATH} does not exist.`);
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Create the readline interface
|
|
30
|
-
const rl = readline.createInterface({
|
|
31
|
-
input: process.stdin,
|
|
32
|
-
output: process.stdout,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Introduction text
|
|
36
|
-
console.log(`
|
|
37
|
-
Welcome to the Spec-Up-T Starterpack configuration tool!
|
|
38
|
-
|
|
39
|
-
You will be asked a series of questions to customize your project.
|
|
40
|
-
Here’s what each field means:
|
|
41
|
-
- "Title": The name of your project.
|
|
42
|
-
- "Description": A brief explanation of your project.
|
|
43
|
-
- "Author": The name of the person or organization creating the project.
|
|
44
|
-
- "Account": The GitHub account or organization where the repository will be hosted.
|
|
45
|
-
- "Repo": The name of the GitHub repository.
|
|
46
|
-
|
|
47
|
-
Note: "Author" refers to the creator of the project, while "Account" refers to the GitHub account or organization.
|
|
48
|
-
|
|
49
|
-
Press Enter to accept the default value shown in parentheses.
|
|
50
|
-
`);
|
|
51
|
-
|
|
52
|
-
// Questions for user input
|
|
53
|
-
const questions = [
|
|
54
|
-
{ field: 'title', prompt: 'Enter title: ', default: 'Spec-Up-T Starterpack' },
|
|
55
|
-
{ field: 'description', prompt: 'Enter description: ', default: 'Create technical specifications in markdown. Based on the original Spec-Up, extended with Terminology tooling' },
|
|
56
|
-
{ field: 'author', prompt: 'Enter author: ', default: 'Trust over IP Foundation' },
|
|
57
|
-
{ field: 'account', prompt: 'Enter account: ', default: 'trustoverip' },
|
|
58
|
-
{ field: 'repo', prompt: 'Enter repo: ', default: 'spec-up-t-starter-pack' },
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
const userResponses = {};
|
|
62
|
-
|
|
63
|
-
// Function to prompt the user for inputs
|
|
64
|
-
function collectUserInputs(index = 0) {
|
|
65
|
-
if (index === questions.length) {
|
|
66
|
-
rl.close();
|
|
67
|
-
applySpecFieldsToJSON();
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const { prompt, default: defaultValue } = questions[index];
|
|
72
|
-
rl.question(`${prompt} (${defaultValue}): `, (answer) => {
|
|
73
|
-
userResponses[questions[index].field] = answer || defaultValue;
|
|
74
|
-
collectUserInputs(index + 1);
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Function to update JSON with user-provided spec fields
|
|
79
|
-
function applySpecFieldsToJSON() {
|
|
80
|
-
try {
|
|
81
|
-
const data = JSON.parse(fs.readFileSync(JSON_FILE_PATH, 'utf8'));
|
|
82
|
-
|
|
83
|
-
if (!data[SPECS_KEY] || !Array.isArray(data[SPECS_KEY]) || !data[SPECS_KEY][0]) {
|
|
84
|
-
console.error(`Error: Invalid JSON structure. "${SPECS_KEY}[0]" is missing.`);
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Ensure the "source" key exists in the JSON object
|
|
89
|
-
if (!data[SPECS_KEY][0].source) {
|
|
90
|
-
data[SPECS_KEY][0].source = {};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Iterate over user responses and assign fields accordingly
|
|
94
|
-
Object.entries(userResponses).forEach(([field, value]) => {
|
|
95
|
-
if (['account', 'repo'].includes(field)) {
|
|
96
|
-
// Add these fields to the "source" key
|
|
97
|
-
data[SPECS_KEY][0].source[field] = value;
|
|
98
|
-
} else {
|
|
99
|
-
// Add all other fields to the root of the JSON object
|
|
100
|
-
data[SPECS_KEY][0][field] = value;
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
fs.writeFileSync(JSON_FILE_PATH, JSON.stringify(data, null, 2), 'utf8');
|
|
105
|
-
console.log(`Successfully updated ${JSON_FILE_PATH}.`);
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error(`Error: Could not update ${JSON_FILE_PATH}.`, error.message);
|
|
108
|
-
process.exit(1);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Start user input collection
|
|
113
|
-
collectUserInputs();
|
|
12
|
+
module.exports = configurator;
|
package/src/create-docx.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs-extra');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { JSDOM } = require('jsdom');
|
|
4
4
|
const { Document, Packer, Paragraph, TextRun, HeadingLevel, TableOfContents, Table, TableRow, TableCell, WidthType, AlignmentType } = require('docx');
|
|
5
|
+
const Logger = require('./utils/logger');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Creates DOCX metadata from config
|
|
@@ -249,7 +250,7 @@ function createTitlePage(config) {
|
|
|
249
250
|
|
|
250
251
|
(async () => {
|
|
251
252
|
try {
|
|
252
|
-
|
|
253
|
+
Logger.info('Starting DOCX generation...');
|
|
253
254
|
|
|
254
255
|
// Read and parse the specs.json file
|
|
255
256
|
const config = fs.readJsonSync('specs.json');
|
|
@@ -261,8 +262,8 @@ function createTitlePage(config) {
|
|
|
261
262
|
|
|
262
263
|
// Check if HTML file exists
|
|
263
264
|
if (!fs.existsSync(filePath)) {
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
Logger.error(`HTML file not found at ${filePath}`);
|
|
266
|
+
Logger.info('Please run "npm run render" first to generate the HTML file.');
|
|
266
267
|
return;
|
|
267
268
|
}
|
|
268
269
|
|
|
@@ -324,9 +325,9 @@ function createTitlePage(config) {
|
|
|
324
325
|
// Write the DOCX file
|
|
325
326
|
fs.writeFileSync(docxPath, buffer);
|
|
326
327
|
|
|
327
|
-
|
|
328
|
+
Logger.success('DOCX generated successfully! Find the DOCX file in the docs directory.');
|
|
328
329
|
} catch (error) {
|
|
329
|
-
|
|
330
|
-
|
|
330
|
+
Logger.error('Error generating DOCX:', error);
|
|
331
|
+
process.exit(1);
|
|
331
332
|
}
|
|
332
333
|
})();
|
package/src/create-pdf.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs-extra');
|
|
|
2
2
|
const puppeteer = require('puppeteer');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const pdfLib = require('pdf-lib');
|
|
5
|
+
const Logger = require('./utils/logger');
|
|
5
6
|
|
|
6
7
|
// ISO compliance configuration
|
|
7
8
|
const ISO_CONFIG = {
|
|
@@ -197,7 +198,7 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
197
198
|
// Insert the TOC after the title section
|
|
198
199
|
document.body.insertBefore(tocContainer, titleWrapper.nextSibling);
|
|
199
200
|
|
|
200
|
-
|
|
201
|
+
console.log('Generated a Table of Contents with ' + headings.length + ' entries.');
|
|
201
202
|
}
|
|
202
203
|
}
|
|
203
204
|
}, logo, logoLink, title, description);
|
|
@@ -253,7 +254,7 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
253
254
|
|
|
254
255
|
// If TOC doesn't exist, we'll need to create one
|
|
255
256
|
if (!document.getElementById('toc')) {
|
|
256
|
-
|
|
257
|
+
console.log('No TOC found in the document. Will create one.');
|
|
257
258
|
}
|
|
258
259
|
});
|
|
259
260
|
|
|
@@ -377,7 +378,7 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
377
378
|
});
|
|
378
379
|
|
|
379
380
|
// Special handling for ALL transcluded terms with blue background - no class restrictions
|
|
380
|
-
document.querySelectorAll('.
|
|
381
|
+
document.querySelectorAll('.term-external, .term-local').forEach(el => {
|
|
381
382
|
// Use the most aggressive approach possible to override the blue background
|
|
382
383
|
el.setAttribute('style', el.getAttribute('style') + '; background: transparent !important; background-color: transparent !important; background-image: none !important;');
|
|
383
384
|
|
|
@@ -390,10 +391,10 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
390
391
|
// Remove any inline styles that might be setting backgrounds
|
|
391
392
|
document.querySelectorAll('style').forEach(styleTag => {
|
|
392
393
|
let cssText = styleTag.textContent;
|
|
393
|
-
// If the style tag contains
|
|
394
|
-
if (cssText.includes('
|
|
395
|
-
cssText = cssText.replace(/dt\.
|
|
396
|
-
'dt.
|
|
394
|
+
// If the style tag contains term-external styles, modify them
|
|
395
|
+
if (cssText.includes('term-external') && cssText.includes('background')) {
|
|
396
|
+
cssText = cssText.replace(/dt\.term-external[^}]+}/g,
|
|
397
|
+
'dt.term-external, dd.term-external, dt.term-local, dd.term-local { background: transparent !important; background-color: transparent !important; background-image: none !important; }');
|
|
397
398
|
styleTag.textContent = cssText;
|
|
398
399
|
}
|
|
399
400
|
}); // Format Table of Contents for book-like layout
|
|
@@ -507,7 +508,7 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
507
508
|
}
|
|
508
509
|
});
|
|
509
510
|
|
|
510
|
-
|
|
511
|
+
Logger.process('Generating PDF with proper TOC page numbers...');
|
|
511
512
|
|
|
512
513
|
// First, generate a draft PDF to calculate the page positions of each heading
|
|
513
514
|
const draftPdfBuffer = await page.pdf({
|
|
@@ -642,7 +643,7 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
642
643
|
|
|
643
644
|
await browser.close();
|
|
644
645
|
|
|
645
|
-
|
|
646
|
+
Logger.success('PDF generated by Puppeteer. Processing with pdf-lib for ISO compliance...');
|
|
646
647
|
|
|
647
648
|
// Optimize PDF with pdf-lib for ISO compliance
|
|
648
649
|
try {
|
|
@@ -658,7 +659,7 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
658
659
|
pdfDoc.setCreationDate(metadata.creationDate);
|
|
659
660
|
pdfDoc.setModificationDate(metadata.modificationDate);
|
|
660
661
|
|
|
661
|
-
|
|
662
|
+
Logger.success('ISO metadata applied successfully.');
|
|
662
663
|
|
|
663
664
|
// Save with conservative settings to ensure compatibility
|
|
664
665
|
const optimizedPdfBytes = await pdfDoc.save({
|
|
@@ -667,15 +668,15 @@ async function createTOCIfNeeded(page, logo, logoLink, title, description) {
|
|
|
667
668
|
});
|
|
668
669
|
|
|
669
670
|
fs.writeFileSync('docs/index.pdf', optimizedPdfBytes);
|
|
670
|
-
|
|
671
|
+
Logger.success('PDF saved with ISO compliance features.');
|
|
671
672
|
} catch (pdfError) {
|
|
672
|
-
|
|
673
|
+
Logger.warn('Could not apply ISO metadata, saving original PDF: %s', pdfError.message);
|
|
673
674
|
// Fallback: save the original PDF if post-processing fails
|
|
674
675
|
fs.writeFileSync('docs/index.pdf', pdfBuffer);
|
|
675
676
|
}
|
|
676
677
|
|
|
677
|
-
|
|
678
|
+
Logger.success('PDF generated successfully! Find the PDF in the docs directory.');
|
|
678
679
|
} catch (error) {
|
|
679
|
-
|
|
680
|
+
Logger.error('Error generating PDF: %o', error);
|
|
680
681
|
}
|
|
681
682
|
})();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file freeze-spec-data.js
|
|
3
|
+
* @description Reads the output path from specs.json, finds the highest versioned directory
|
|
4
|
+
* in the destination path, and copies index.html to a new directory with an incremented version.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const Logger = require('./utils/logger');
|
|
10
|
+
const { versions } = require('./utils/regex-patterns');
|
|
11
|
+
|
|
12
|
+
const config = fs.readJsonSync('specs.json');
|
|
13
|
+
const outputPath = config.specs[0].output_path;
|
|
14
|
+
|
|
15
|
+
const sourceFile = path.join(outputPath, 'index.html');
|
|
16
|
+
const destDir = path.join(outputPath, 'versions');
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(destDir)) {
|
|
19
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const dirs = fs.readdirSync(destDir).filter(file => fs.statSync(path.join(destDir, file)).isDirectory());
|
|
23
|
+
let highestVersion = 0;
|
|
24
|
+
const versionPattern = versions.pattern;
|
|
25
|
+
|
|
26
|
+
dirs.forEach(dir => {
|
|
27
|
+
const match = dir.match(versionPattern);
|
|
28
|
+
if (match) {
|
|
29
|
+
const version = parseInt(match[1], 10);
|
|
30
|
+
if (version > highestVersion) {
|
|
31
|
+
highestVersion = version;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const newVersion = highestVersion + 1;
|
|
37
|
+
const newVersionDir = path.join(destDir, `v${newVersion}`);
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(newVersionDir)) {
|
|
40
|
+
fs.mkdirSync(newVersionDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const destFile = path.join(newVersionDir, 'index.html');
|
|
44
|
+
fs.copyFileSync(sourceFile, destFile);
|
|
45
|
+
|
|
46
|
+
Logger.success(`Created a freezed specification version in ${destFile}`);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Test file for git-info utility functions
|
|
3
|
+
* This test verifies that the GitHub repository information
|
|
4
|
+
* is correctly extracted and formatted for the meta tag.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { getCurrentBranch, getGithubRepoInfo } = require('./utils/git-info');
|
|
8
|
+
|
|
9
|
+
// Tests for extracting and formatting Git repository information
|
|
10
|
+
describe('git-info utility', () => {
|
|
11
|
+
// Tests for getting the current Git branch name
|
|
12
|
+
describe('getCurrentBranch', () => {
|
|
13
|
+
// Test: Does the function return a valid branch name as a string?
|
|
14
|
+
test('should return a string branch name', () => {
|
|
15
|
+
const branch = getCurrentBranch();
|
|
16
|
+
expect(typeof branch).toBe('string');
|
|
17
|
+
expect(branch.length).toBeGreaterThan(0);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Test: Is the branch name properly formatted (no whitespace)?
|
|
21
|
+
test('should not contain newlines or spaces', () => {
|
|
22
|
+
const branch = getCurrentBranch();
|
|
23
|
+
expect(branch).not.toMatch(/\n|\r|\s/);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Tests for formatting GitHub repository information for meta tags
|
|
28
|
+
describe('getGithubRepoInfo', () => {
|
|
29
|
+
// Test: Can the system format complete repository information correctly?
|
|
30
|
+
test('should format github repo info correctly with valid spec', () => {
|
|
31
|
+
const spec = {
|
|
32
|
+
source: {
|
|
33
|
+
account: 'testuser',
|
|
34
|
+
repo: 'testrepo'
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const repoInfo = getGithubRepoInfo(spec);
|
|
39
|
+
expect(repoInfo).toMatch(/^testuser,testrepo,.+$/);
|
|
40
|
+
|
|
41
|
+
const parts = repoInfo.split(',');
|
|
42
|
+
expect(parts).toHaveLength(3);
|
|
43
|
+
expect(parts[0]).toBe('testuser');
|
|
44
|
+
expect(parts[1]).toBe('testrepo');
|
|
45
|
+
expect(parts[2].length).toBeGreaterThan(0);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Test: Does the system gracefully handle missing repository information?
|
|
49
|
+
test('should handle missing source object', () => {
|
|
50
|
+
const spec = {};
|
|
51
|
+
const repoInfo = getGithubRepoInfo(spec);
|
|
52
|
+
expect(repoInfo).toMatch(/^unknown,unknown,.+$/);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Test: Can the system handle incomplete repository information?
|
|
56
|
+
test('should handle partial source information', () => {
|
|
57
|
+
const spec = {
|
|
58
|
+
source: {
|
|
59
|
+
account: 'onlyuser'
|
|
60
|
+
// missing repo
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const repoInfo = getGithubRepoInfo(spec);
|
|
65
|
+
expect(repoInfo).toMatch(/^onlyuser,unknown,.+$/);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Test: Does the system follow best practices for meta tag naming?
|
|
69
|
+
test('should use spec-up-t namespace prefix recommendation', () => {
|
|
70
|
+
// This test verifies our implementation follows the best practice
|
|
71
|
+
// of using namespaced property names as recommended in the user request
|
|
72
|
+
const metaTagProperty = 'spec-up-t:github-repo-info';
|
|
73
|
+
expect(metaTagProperty).toMatch(/^spec-up-t:/);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -12,6 +12,8 @@ const fs = require('fs');
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const { spawnSync } = require('child_process');
|
|
14
14
|
const fileOpener = require('../utils/file-opener');
|
|
15
|
+
const Logger = require('../utils/logger');
|
|
16
|
+
const { utils } = require('../utils/regex-patterns');
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* Checks if a path is gitignored
|
|
@@ -30,7 +32,7 @@ function isPathGitIgnored(projectRoot, targetPath) {
|
|
|
30
32
|
});
|
|
31
33
|
return result.status === 0; // Path is ignored (command exited with status 0)
|
|
32
34
|
} catch (error) {
|
|
33
|
-
|
|
35
|
+
Logger.info(`Error checking if path is gitignored: ${error.message}`);
|
|
34
36
|
return false; // Path is not ignored (command exited with non-zero status)
|
|
35
37
|
}
|
|
36
38
|
}
|
|
@@ -208,7 +210,7 @@ function findOutputDirIgnorePatterns(lines, normalizedPath, dirName) {
|
|
|
208
210
|
// Check for wildcards covering all directories
|
|
209
211
|
trimmedLine === '*/' ||
|
|
210
212
|
// Check for wildcards that might match our path using regex
|
|
211
|
-
(trimmedLine.includes('*') &&
|
|
213
|
+
(trimmedLine.includes('*') && utils.createGitignoreRegex(trimmedLine).test(normalizedPath))
|
|
212
214
|
) {
|
|
213
215
|
dirIgnorePatterns.push(trimmedLine);
|
|
214
216
|
}
|
|
@@ -398,7 +400,7 @@ async function checkDestinationGitIgnore(projectRoot) {
|
|
|
398
400
|
|
|
399
401
|
return results;
|
|
400
402
|
} catch (error) {
|
|
401
|
-
|
|
403
|
+
Logger.error('Error checking final destination directory gitignore status:', error);
|
|
402
404
|
return [{
|
|
403
405
|
name: 'Final destination directory gitignore check',
|
|
404
406
|
success: false,
|
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const https = require('https');
|
|
4
4
|
const url = require('url');
|
|
5
|
+
const Logger = require('../utils/logger');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Check if a given URL has correct GitHub Pages structure
|
|
@@ -17,7 +18,7 @@ function isValidGitHubPagesUrl(urlStr) {
|
|
|
17
18
|
parsedUrl.hostname.endsWith('.github.io')
|
|
18
19
|
);
|
|
19
20
|
} catch (error) {
|
|
20
|
-
|
|
21
|
+
Logger.error(`Error validating GitHub Pages URL: ${error.message}`);
|
|
21
22
|
return false;
|
|
22
23
|
}
|
|
23
24
|
}
|
|
@@ -35,7 +36,7 @@ function isValidGitHubRepoUrl(urlStr) {
|
|
|
35
36
|
parsedUrl.pathname.split('/').filter(Boolean).length >= 2
|
|
36
37
|
);
|
|
37
38
|
} catch (error) {
|
|
38
|
-
|
|
39
|
+
Logger.error(`Error validating GitHub repo URL: ${error.message}`);
|
|
39
40
|
return false;
|
|
40
41
|
}
|
|
41
42
|
}
|
|
@@ -71,7 +72,7 @@ function urlExists(urlStr) {
|
|
|
71
72
|
|
|
72
73
|
req.end();
|
|
73
74
|
} catch (error) {
|
|
74
|
-
|
|
75
|
+
Logger.error(`URL Format Error: Invalid URL format for ${urlStr} - ${error.message}`);
|
|
75
76
|
resolve(false);
|
|
76
77
|
}
|
|
77
78
|
});
|
|
@@ -272,7 +273,7 @@ async function checkExternalSpecs(projectRoot) {
|
|
|
272
273
|
|
|
273
274
|
return allResults;
|
|
274
275
|
} catch (error) {
|
|
275
|
-
|
|
276
|
+
Logger.error('Error checking external specs:', error);
|
|
276
277
|
return [{
|
|
277
278
|
name: 'External specs check',
|
|
278
279
|
success: false,
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
const fs = require('fs');
|
|
31
31
|
const path = require('path');
|
|
32
|
+
const Logger = require('../utils/logger');
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* Field descriptions for specs.json keys
|
|
@@ -372,7 +373,7 @@ async function checkSpecsJsonConfiguration(projectRoot) {
|
|
|
372
373
|
return [...results, ...summaryResults];
|
|
373
374
|
|
|
374
375
|
} catch (error) {
|
|
375
|
-
|
|
376
|
+
Logger.error('Error checking specs.json configuration:', error);
|
|
376
377
|
return [{
|
|
377
378
|
name: 'specs.json configuration check',
|
|
378
379
|
success: false,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const Logger = require('../utils/logger');
|
|
4
|
+
const { externalReferences } = require('../utils/regex-patterns');
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Extracts the spec name from a tref tag at the beginning of a markdown file
|
|
@@ -13,13 +15,13 @@ function extractSpecNameFromTref(firstLine) {
|
|
|
13
15
|
|
|
14
16
|
try {
|
|
15
17
|
// Extract content between [[tref: and the next comma
|
|
16
|
-
const match = firstLine.match(
|
|
18
|
+
const match = firstLine.match(externalReferences.trefSpecExtractor);
|
|
17
19
|
if (match && match[1]) {
|
|
18
20
|
// Trim whitespace
|
|
19
21
|
return match[1].trim();
|
|
20
22
|
}
|
|
21
23
|
} catch (error) {
|
|
22
|
-
|
|
24
|
+
Logger.error('Error extracting spec name from tref:', error);
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
return null;
|
|
@@ -254,7 +256,7 @@ async function checkTermReferences(projectRoot) {
|
|
|
254
256
|
|
|
255
257
|
return results;
|
|
256
258
|
} catch (error) {
|
|
257
|
-
|
|
259
|
+
Logger.error('Error checking term references:', error);
|
|
258
260
|
return [{
|
|
259
261
|
name: 'Term references check',
|
|
260
262
|
success: false,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const Logger = require('../utils/logger');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Check if the terms-and-definitions-intro.md file exists in the spec directory
|
|
@@ -67,7 +68,7 @@ async function checkTermsIntroFile(projectRoot) {
|
|
|
67
68
|
|
|
68
69
|
return results;
|
|
69
70
|
} catch (error) {
|
|
70
|
-
|
|
71
|
+
Logger.error('Error checking terms-and-definitions-intro.md file:', error);
|
|
71
72
|
return [{
|
|
72
73
|
name: 'Terms intro file check',
|
|
73
74
|
success: false,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { shouldProcessFile } = require('../utils/file-filter');
|
|
4
|
+
const Logger = require('../utils/logger');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Extracts the spec name and term from a tref tag at the beginning of a markdown file
|
|
@@ -33,7 +34,7 @@ function extractTrefInfo(firstLine) {
|
|
|
33
34
|
|
|
34
35
|
return { repo, term };
|
|
35
36
|
} catch (error) {
|
|
36
|
-
|
|
37
|
+
Logger.error('Error extracting tref info:', error);
|
|
37
38
|
return null;
|
|
38
39
|
}
|
|
39
40
|
}
|
|
@@ -55,7 +56,7 @@ function findAllCacheFiles(cacheDir) {
|
|
|
55
56
|
|
|
56
57
|
return files;
|
|
57
58
|
} catch (error) {
|
|
58
|
-
|
|
59
|
+
Logger.error(`Error finding cache files:`, error);
|
|
59
60
|
return [];
|
|
60
61
|
}
|
|
61
62
|
}
|
|
@@ -76,7 +77,7 @@ function termExistsInRepo(filePath, term) {
|
|
|
76
77
|
|
|
77
78
|
// Check if the file has a terms array
|
|
78
79
|
if (!cacheData?.terms?.length) {
|
|
79
|
-
|
|
80
|
+
Logger.warn(`Cache file ${filePath} has no terms array`);
|
|
80
81
|
return false;
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -102,7 +103,7 @@ function termExistsInRepo(filePath, term) {
|
|
|
102
103
|
|
|
103
104
|
return false;
|
|
104
105
|
} catch (error) {
|
|
105
|
-
|
|
106
|
+
Logger.error(`Error checking if term exists in file ${filePath}:`, error);
|
|
106
107
|
return false;
|
|
107
108
|
}
|
|
108
109
|
}
|
|
@@ -137,7 +138,7 @@ function findRepoForCacheFile(filePath, externalSpecs) {
|
|
|
137
138
|
|
|
138
139
|
return null;
|
|
139
140
|
} catch (error) {
|
|
140
|
-
|
|
141
|
+
Logger.error(`Error finding repository for cache file ${filePath}:`, error);
|
|
141
142
|
return null; // Could not determine repository due to error reading or parsing cache file
|
|
142
143
|
}
|
|
143
144
|
}
|
|
@@ -218,7 +219,7 @@ function findCacheFileForRepo(cacheDir, specConfig) {
|
|
|
218
219
|
|
|
219
220
|
return null;
|
|
220
221
|
} catch (error) {
|
|
221
|
-
|
|
222
|
+
Logger.error(`Error finding cache file for repo:`, error);
|
|
222
223
|
return null;
|
|
223
224
|
}
|
|
224
225
|
}
|
|
@@ -534,7 +535,7 @@ async function checkTrefTerms(projectRoot) {
|
|
|
534
535
|
|
|
535
536
|
return results;
|
|
536
537
|
} catch (error) {
|
|
537
|
-
|
|
538
|
+
Logger.error('Error checking tref terms:', error);
|
|
538
539
|
return [{
|
|
539
540
|
name: 'Term reference validation check',
|
|
540
541
|
success: false,
|
package/src/health-check.js
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
|
|
45
45
|
const fs = require('fs');
|
|
46
46
|
const path = require('path');
|
|
47
|
+
const Logger = require('./utils/logger');
|
|
47
48
|
const https = require('https');
|
|
48
49
|
const fileOpener = require('./utils/file-opener');
|
|
49
50
|
|
|
@@ -112,7 +113,7 @@ async function getRepoInfo() {
|
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
115
|
} catch (error) {
|
|
115
|
-
|
|
116
|
+
Logger.error('Error reading boilerplate specs.json:', error);
|
|
116
117
|
}
|
|
117
118
|
}
|
|
118
119
|
|
|
@@ -176,10 +177,10 @@ async function getRepoInfo() {
|
|
|
176
177
|
}
|
|
177
178
|
}
|
|
178
179
|
} else {
|
|
179
|
-
|
|
180
|
+
Logger.info('specs.json not found');
|
|
180
181
|
}
|
|
181
182
|
} catch (error) {
|
|
182
|
-
|
|
183
|
+
Logger.error('Error reading specs.json:', error);
|
|
183
184
|
}
|
|
184
185
|
|
|
185
186
|
// Return default values if specs.json doesn't exist or doesn't contain the required information
|
|
@@ -221,19 +222,19 @@ function checkRepositoryExists(host, account, repo) {
|
|
|
221
222
|
});
|
|
222
223
|
|
|
223
224
|
request.on('error', (error) => {
|
|
224
|
-
|
|
225
|
+
Logger.error('Error checking repository existence:', error.message);
|
|
225
226
|
resolve(false);
|
|
226
227
|
});
|
|
227
228
|
|
|
228
229
|
request.on('timeout', () => {
|
|
229
|
-
|
|
230
|
+
Logger.error('Timeout checking repository existence');
|
|
230
231
|
request.destroy();
|
|
231
232
|
resolve(false);
|
|
232
233
|
});
|
|
233
234
|
|
|
234
235
|
request.end();
|
|
235
236
|
} catch (error) {
|
|
236
|
-
|
|
237
|
+
Logger.error('Error checking repository existence:', error.message);
|
|
237
238
|
resolve(false);
|
|
238
239
|
}
|
|
239
240
|
});
|
|
@@ -345,7 +346,7 @@ function getStatusDisplay(result) {
|
|
|
345
346
|
* }
|
|
346
347
|
*/
|
|
347
348
|
async function runHealthCheck() {
|
|
348
|
-
|
|
349
|
+
Logger.info('Running health checks...');
|
|
349
350
|
|
|
350
351
|
// Collection to store all check results
|
|
351
352
|
const results = [];
|