spec-up-t 1.2.6 → 1.2.8
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 +3 -0
- package/assets/js/collapse-definitions.js +2 -1
- package/index.js +11 -1
- package/jest.config.js +20 -0
- package/package.json +3 -2
- package/src/collect-external-references.js +10 -23
- package/src/escape-mechanism.js +57 -0
- package/src/health-check/{output-gitignore-checker.js → destination-gitignore-checker.js} +40 -25
- package/src/health-check/specs-configuration-checker.js +178 -144
- package/src/health-check.js +237 -48
- package/src/utils/README.md +35 -0
- package/src/utils/file-opener.js +89 -0
- package/branches.md +0 -17
- package/src/README.md +0 -98
- package/src/collectExternalReferences/fetchTermsFromIndex.1.js +0 -340
package/index.js
CHANGED
|
@@ -35,6 +35,7 @@ module.exports = async function (options = {}) {
|
|
|
35
35
|
createVersionsIndex(config.specs[0].output_path);
|
|
36
36
|
|
|
37
37
|
const { fixMarkdownFiles } = require('./src/fix-markdown-files.js');
|
|
38
|
+
const { processEscapedTags, restoreEscapedTags } = require('./src/escape-mechanism.js');
|
|
38
39
|
|
|
39
40
|
let template = fs.readFileSync(path.join(modulePath, 'templates/template.html'), 'utf8');
|
|
40
41
|
let assets = fs.readJsonSync(modulePath + '/config/asset-map.json');
|
|
@@ -528,7 +529,12 @@ module.exports = async function (options = {}) {
|
|
|
528
529
|
|
|
529
530
|
let doc = docs.join("\n");
|
|
530
531
|
|
|
531
|
-
//
|
|
532
|
+
// Handles backslash escape mechanism for substitution tags
|
|
533
|
+
// Phase 1: Pre-processing - Handle escaped tags
|
|
534
|
+
doc = processEscapedTags(doc);
|
|
535
|
+
|
|
536
|
+
// Handles backslash escape mechanism for substitution tags
|
|
537
|
+
// Phase 2: Tag Processing - Apply normal substitution logic
|
|
532
538
|
doc = applyReplacers(doc);
|
|
533
539
|
|
|
534
540
|
md[spec.katex ? "enable" : "disable"](katexRules);
|
|
@@ -542,6 +548,10 @@ module.exports = async function (options = {}) {
|
|
|
542
548
|
// Sort definition terms case-insensitively before final rendering
|
|
543
549
|
renderedHtml = sortDefinitionTermsInHtml(renderedHtml);
|
|
544
550
|
|
|
551
|
+
// Handles backslash escape mechanism for substitution tags
|
|
552
|
+
// Phase 3: Post-processing - Restore escaped sequences as literals
|
|
553
|
+
renderedHtml = restoreEscapedTags(renderedHtml);
|
|
554
|
+
|
|
545
555
|
// Process external references to ensure they are inserted as raw HTML, not as JSON string
|
|
546
556
|
const externalReferencesHtml = Array.isArray(externalReferences)
|
|
547
557
|
? externalReferences.join('')
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
collectCoverageFrom: [
|
|
3
|
+
'src/**/*.{js,jsx}',
|
|
4
|
+
'!src/**/*.test.{js,jsx}',
|
|
5
|
+
'!src/**/__tests__/**',
|
|
6
|
+
'!src/**/__mocks__/**',
|
|
7
|
+
],
|
|
8
|
+
coverageDirectory: 'coverage',
|
|
9
|
+
coverageReporters: ['text', 'lcov', 'html'],
|
|
10
|
+
coverageThreshold: {
|
|
11
|
+
global: {
|
|
12
|
+
branches: 80,
|
|
13
|
+
functions: 80,
|
|
14
|
+
lines: 80,
|
|
15
|
+
statements: 80,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
testEnvironment: 'node',
|
|
19
|
+
verbose: true,
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-up-t",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"description": "Technical specification drafting tool that generates rich specification documents from markdown. Forked from https://github.com/decentralized-identity/spec-up by Daniel Buchner (https://github.com/csuwildcat)",
|
|
5
5
|
"main": "./index",
|
|
6
6
|
"repository": {
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"jest": "^29.7.0"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
|
-
"test": "
|
|
73
|
+
"test": "jest",
|
|
74
|
+
"test:coverage": "jest --coverage"
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -270,13 +270,17 @@ function processExternalReferences(config, GITHUB_API_TOKEN, options) {
|
|
|
270
270
|
*
|
|
271
271
|
* @description
|
|
272
272
|
* This function performs several key operations:
|
|
273
|
-
* 1.
|
|
273
|
+
* 1. Optionally uses GitHub PAT for better API performance and higher rate limits
|
|
274
274
|
* 2. Checks validity of repository URLs
|
|
275
275
|
* 3. Extracts xref/tref patterns from markdown content
|
|
276
276
|
* 4. Extends references with repository metadata
|
|
277
277
|
* 5. Processes references to fetch commit information
|
|
278
278
|
* 6. Generates output files in both JS and JSON formats
|
|
279
279
|
*
|
|
280
|
+
* Note: The function will run without a GitHub token but may encounter rate limits.
|
|
281
|
+
* For better performance, provide a GitHub Personal Access Token via environment
|
|
282
|
+
* variable or the options parameter.
|
|
283
|
+
*
|
|
280
284
|
* @example
|
|
281
285
|
* // Basic usage
|
|
282
286
|
* collectExternalReferences();
|
|
@@ -289,17 +293,6 @@ function collectExternalReferences(options = {}) {
|
|
|
289
293
|
const externalSpecsRepos = config.specs[0].external_specs;
|
|
290
294
|
const GITHUB_API_TOKEN = options.pat || process.env.GITHUB_API_TOKEN;
|
|
291
295
|
|
|
292
|
-
const explanationPAT =
|
|
293
|
-
`❌ No GitHub Personal Access Token (PAT) was found.
|
|
294
|
-
|
|
295
|
-
GitHub requires you to set up a PAT to retrieve external references.
|
|
296
|
-
|
|
297
|
-
There is no point in continuing without a PAT, so we stop here.
|
|
298
|
-
|
|
299
|
-
Find instructions on how to get a PAT at https://blockchainbird.github.io/spec-up-t-website/docs/getting-started/github-token
|
|
300
|
-
|
|
301
|
-
`;
|
|
302
|
-
|
|
303
296
|
const explanationNoExternalReferences =
|
|
304
297
|
`❌ No external references were found in the specs.json file.
|
|
305
298
|
|
|
@@ -310,19 +303,13 @@ function collectExternalReferences(options = {}) {
|
|
|
310
303
|
`;
|
|
311
304
|
|
|
312
305
|
// First do some checks
|
|
313
|
-
|
|
314
|
-
// Do not run the script if the GitHub API token is not set
|
|
306
|
+
// Show informational message if no token is available
|
|
315
307
|
if (!GITHUB_API_TOKEN) {
|
|
316
|
-
console.log(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
// React to user pressing any key
|
|
320
|
-
if (userInput.trim() !== '') {
|
|
321
|
-
console.log('ℹ️ Stopping...');
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
308
|
+
console.log('ℹ️ No GitHub Personal Access Token (PAT) found. Running without authentication (may hit rate limits).');
|
|
309
|
+
console.log('💡 For better performance, set up a PAT: https://blockchainbird.github.io/spec-up-t-website/docs/getting-started/github-token\n');
|
|
324
310
|
}
|
|
325
|
-
|
|
311
|
+
|
|
312
|
+
if (externalSpecsRepos.length === 0) {
|
|
326
313
|
// Check if the URLs for the external specs repositories are valid, and prompt the user to abort if they are not.
|
|
327
314
|
console.log(explanationNoExternalReferences);
|
|
328
315
|
const userInput = readlineSync.question('Press any key');
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape Mechanism Module for Spec-Up Substitution Tags
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to handle backslash escape sequences for substitution tags,
|
|
5
|
+
* allowing users to display tag syntax literally in their documentation.
|
|
6
|
+
*
|
|
7
|
+
* The escape mechanism works in three phases:
|
|
8
|
+
* 1. Pre-processing: Convert escaped sequences to temporary placeholders
|
|
9
|
+
* 2. Tag processing: Normal substitution logic (handled elsewhere)
|
|
10
|
+
* 3. Post-processing: Restore escaped sequences as literals
|
|
11
|
+
*
|
|
12
|
+
* Supported escape pattern:
|
|
13
|
+
* - \[[tag: content]] → displays as literal [[tag: content]]
|
|
14
|
+
*
|
|
15
|
+
* @version 1.0.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handles backslash escape mechanism for substitution tags
|
|
20
|
+
*
|
|
21
|
+
* Use backslash escape sequences to allow literal [[ tags in markdown
|
|
22
|
+
*
|
|
23
|
+
* Phase 1: Pre-processing - Convert escaped sequences to temporary placeholders
|
|
24
|
+
*
|
|
25
|
+
* @param {string} doc - The markdown document to process
|
|
26
|
+
* @returns {string} - Document with escaped sequences converted to placeholders
|
|
27
|
+
*/
|
|
28
|
+
function processEscapedTags(doc) {
|
|
29
|
+
// Replace \[[ with escape placeholder for literal display
|
|
30
|
+
// In markdown: \[[def: term]] should become [[def: term]] (literal tag syntax)
|
|
31
|
+
doc = doc.replace(/\\(\[\[)/g, '__SPEC_UP_ESCAPED_TAG__');
|
|
32
|
+
|
|
33
|
+
return doc;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Handles backslash escape mechanism for substitution tags
|
|
38
|
+
*
|
|
39
|
+
* Use backslash escape sequences to allow literal [[ tags in markdown
|
|
40
|
+
*
|
|
41
|
+
* Phase 3: Post-processing - Restore escaped sequences as literals
|
|
42
|
+
* Converts placeholders back to literal [[ characters
|
|
43
|
+
*
|
|
44
|
+
* @param {string} renderedHtml - The rendered HTML to process
|
|
45
|
+
* @returns {string} - HTML with placeholders restored to literal [[ tags
|
|
46
|
+
*/
|
|
47
|
+
function restoreEscapedTags(renderedHtml) {
|
|
48
|
+
// Replace escaped tag placeholders with literal [[
|
|
49
|
+
renderedHtml = renderedHtml.replace(/__SPEC_UP_ESCAPED_TAG__/g, '[[');
|
|
50
|
+
|
|
51
|
+
return renderedHtml;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
processEscapedTags,
|
|
56
|
+
restoreEscapedTags
|
|
57
|
+
};
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file destination-gitignore-checker.js
|
|
3
|
+
* @description Checks if the final destination directory (from output_path in specs.json)
|
|
4
|
+
* is being ignored by Git. This is the directory where index.html is generated,
|
|
5
|
+
* NOT the temporary .cache directory (formerly called "output").
|
|
6
|
+
*
|
|
7
|
+
* Important: This file deals with concept #1 (output_path from specs.json),
|
|
8
|
+
* not concept #2 (the temporary .cache directory for build artifacts).
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
const fs = require('fs');
|
|
2
12
|
const path = require('path');
|
|
3
|
-
const {
|
|
13
|
+
const { spawnSync } = require('child_process');
|
|
14
|
+
const fileOpener = require('../utils/file-opener');
|
|
4
15
|
|
|
5
16
|
/**
|
|
6
17
|
* Checks if a path is gitignored
|
|
@@ -13,8 +24,11 @@ function isPathGitIgnored(projectRoot, targetPath) {
|
|
|
13
24
|
// Use git check-ignore to determine if the path is ignored
|
|
14
25
|
// If command exits with status 0, path is ignored
|
|
15
26
|
// If command exits with status 1, path is not ignored
|
|
16
|
-
|
|
17
|
-
|
|
27
|
+
const gitPath = fileOpener.getCommandPath('git');
|
|
28
|
+
const result = spawnSync(gitPath, ['-C', projectRoot, 'check-ignore', '-q', targetPath], {
|
|
29
|
+
stdio: 'ignore'
|
|
30
|
+
});
|
|
31
|
+
return result.status === 0; // Path is ignored (command exited with status 0)
|
|
18
32
|
} catch (error) {
|
|
19
33
|
console.log(`Error checking if path is gitignored: ${error.message}`);
|
|
20
34
|
return false; // Path is not ignored (command exited with non-zero status)
|
|
@@ -87,11 +101,11 @@ function extractOutputPath(specsPath) {
|
|
|
87
101
|
}
|
|
88
102
|
|
|
89
103
|
/**
|
|
90
|
-
* Check if the
|
|
104
|
+
* Check if the final destination directory (from output_path) exists
|
|
91
105
|
* @param {string} projectRoot - Root directory of the project
|
|
92
106
|
* @param {string} outputPath - Output path from specs.json
|
|
93
107
|
* @param {string} normalizedPath - Normalized output path
|
|
94
|
-
* @returns {Object} - Result with
|
|
108
|
+
* @returns {Object} - Result with final destination directory check
|
|
95
109
|
*/
|
|
96
110
|
function checkOutputDirExists(projectRoot, outputPath, normalizedPath) {
|
|
97
111
|
// Check if the path exists
|
|
@@ -100,17 +114,17 @@ function checkOutputDirExists(projectRoot, outputPath, normalizedPath) {
|
|
|
100
114
|
|
|
101
115
|
if (!outputPathExists) {
|
|
102
116
|
return {
|
|
103
|
-
name: '
|
|
117
|
+
name: 'Final destination directory existence',
|
|
104
118
|
status: 'warning',
|
|
105
119
|
success: true, // Still considered a "success" for backward compatibility
|
|
106
|
-
details: `
|
|
120
|
+
details: `Final destination directory "${outputPath}" does not exist yet. This is OK if you haven't rendered the specs yet.`
|
|
107
121
|
};
|
|
108
122
|
}
|
|
109
123
|
|
|
110
124
|
return {
|
|
111
|
-
name: '
|
|
125
|
+
name: 'Final destination directory existence',
|
|
112
126
|
success: true,
|
|
113
|
-
details: `
|
|
127
|
+
details: `Final destination directory "${outputPath}" exists`
|
|
114
128
|
};
|
|
115
129
|
}
|
|
116
130
|
|
|
@@ -245,7 +259,7 @@ function findComplexHtmlPatterns(lines) {
|
|
|
245
259
|
}
|
|
246
260
|
|
|
247
261
|
/**
|
|
248
|
-
* Check if HTML files in the
|
|
262
|
+
* Check if HTML files in the final destination directory are being ignored by Git
|
|
249
263
|
* @param {string} projectRoot - Root directory of the project
|
|
250
264
|
* @param {string} normalizedPath - Normalized output path
|
|
251
265
|
* @param {string} outputPath - Original output path
|
|
@@ -273,8 +287,8 @@ function checkHtmlFilesGitignore(projectRoot, normalizedPath, outputPath, releva
|
|
|
273
287
|
name: 'Check if index.html files are gitignored',
|
|
274
288
|
success: !isIndexHtmlIgnored,
|
|
275
289
|
details: isIndexHtmlIgnored
|
|
276
|
-
? `index.html files in the
|
|
277
|
-
: `index.html files in the
|
|
290
|
+
? `index.html files in the final destination directory would be ignored by Git. This is problematic as they're crucial output files.`
|
|
291
|
+
: `index.html files in the final destination directory are properly tracked by Git.`
|
|
278
292
|
});
|
|
279
293
|
|
|
280
294
|
// If index.html is ignored but we couldn't find an explicit pattern, look for more complex patterns
|
|
@@ -295,22 +309,22 @@ function checkHtmlFilesGitignore(projectRoot, normalizedPath, outputPath, releva
|
|
|
295
309
|
}
|
|
296
310
|
|
|
297
311
|
/**
|
|
298
|
-
* Check if
|
|
312
|
+
* Check if final destination directory (from output_path) is being ignored by Git
|
|
299
313
|
* @param {string} projectRoot - Root directory of the project
|
|
300
314
|
* @param {string} normalizedPath - Normalized output path
|
|
301
315
|
* @param {string} outputPath - Original output path
|
|
302
316
|
* @param {string} dirName - Directory name from path
|
|
303
317
|
* @param {Array} relevantLines - Relevant lines from .gitignore
|
|
304
|
-
* @returns {Array} - Results for
|
|
318
|
+
* @returns {Array} - Results for final destination directory gitignore check
|
|
305
319
|
*/
|
|
306
320
|
function checkOutputDirIgnorePatterns(projectRoot, normalizedPath, outputPath, dirName, relevantLines) {
|
|
307
321
|
const dirIgnorePatterns = findOutputDirIgnorePatterns(relevantLines, normalizedPath, dirName);
|
|
308
322
|
|
|
309
323
|
if (dirIgnorePatterns.length > 0) {
|
|
310
324
|
return [{
|
|
311
|
-
name: 'Check if
|
|
325
|
+
name: 'Check if final destination directory is gitignored',
|
|
312
326
|
success: false,
|
|
313
|
-
details: `Found patterns in .gitignore that would ignore the
|
|
327
|
+
details: `Found patterns in .gitignore that would ignore the final destination directory: ${dirIgnorePatterns.join(', ')}. Remove these entries to ensure generated content is tracked.`
|
|
314
328
|
}];
|
|
315
329
|
}
|
|
316
330
|
|
|
@@ -318,20 +332,21 @@ function checkOutputDirIgnorePatterns(projectRoot, normalizedPath, outputPath, d
|
|
|
318
332
|
const isIgnored = isPathGitIgnored(projectRoot, normalizedPath);
|
|
319
333
|
|
|
320
334
|
return [{
|
|
321
|
-
name: 'Check if
|
|
335
|
+
name: 'Check if final destination directory is gitignored',
|
|
322
336
|
success: !isIgnored,
|
|
323
337
|
details: isIgnored
|
|
324
|
-
? `
|
|
325
|
-
: `
|
|
338
|
+
? `Final destination directory "${outputPath}" is being ignored by Git. This could be due to a complex pattern in .gitignore. Remove any entries that might affect this directory.`
|
|
339
|
+
: `Final destination directory "${outputPath}" is not being ignored by Git, which is good.`
|
|
326
340
|
}];
|
|
327
341
|
}
|
|
328
342
|
|
|
329
343
|
/**
|
|
330
|
-
* Check if the
|
|
344
|
+
* Check if the final destination directory (from output_path in specs.json) is being ignored by Git
|
|
345
|
+
* This checks the directory where index.html is generated, NOT the temporary .cache directory
|
|
331
346
|
* @param {string} projectRoot - Root directory of the project
|
|
332
347
|
* @returns {Promise<Array>} - Array of check results
|
|
333
348
|
*/
|
|
334
|
-
async function
|
|
349
|
+
async function checkDestinationGitIgnore(projectRoot) {
|
|
335
350
|
const results = [];
|
|
336
351
|
|
|
337
352
|
try {
|
|
@@ -369,7 +384,7 @@ async function checkOutputDirGitIgnore(projectRoot) {
|
|
|
369
384
|
const relevantLines = getRelevantGitignoreLines(gitignoreContent);
|
|
370
385
|
const dirName = path.basename(normalizedPath);
|
|
371
386
|
|
|
372
|
-
// Check
|
|
387
|
+
// Check final destination directory ignore patterns
|
|
373
388
|
const dirResults = checkOutputDirIgnorePatterns(
|
|
374
389
|
projectRoot, normalizedPath, outputPath, dirName, relevantLines
|
|
375
390
|
);
|
|
@@ -383,9 +398,9 @@ async function checkOutputDirGitIgnore(projectRoot) {
|
|
|
383
398
|
|
|
384
399
|
return results;
|
|
385
400
|
} catch (error) {
|
|
386
|
-
console.error('Error checking
|
|
401
|
+
console.error('Error checking final destination directory gitignore status:', error);
|
|
387
402
|
return [{
|
|
388
|
-
name: '
|
|
403
|
+
name: 'Final destination directory gitignore check',
|
|
389
404
|
success: false,
|
|
390
405
|
details: `Error: ${error.message}`
|
|
391
406
|
}];
|
|
@@ -393,5 +408,5 @@ async function checkOutputDirGitIgnore(projectRoot) {
|
|
|
393
408
|
}
|
|
394
409
|
|
|
395
410
|
module.exports = {
|
|
396
|
-
|
|
411
|
+
checkDestinationGitIgnore
|
|
397
412
|
};
|