spec-up-t 1.1.52 → 1.1.53
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/assets/js/insert-trefs.js +1 -1
- package/branches.md +33 -0
- package/package.json +7 -1
- package/src/README.md +98 -0
- package/src/collect-external-references.js +108 -31
- package/src/collect-external-references.test.js +152 -0
- package/src/collectExternalReferences/fetchTermsFromGitHubRepository.js +39 -44
- package/src/collectExternalReferences/fetchTermsFromGitHubRepository.test.js +385 -0
- package/src/collectExternalReferences/matchTerm.js +10 -5
- package/src/collectExternalReferences/matchTerm.test.js +30 -0
- package/src/collectExternalReferences/octokitClient.js +96 -0
- package/src/collectExternalReferences/processXTrefsData.js +2 -0
- package/src/create-term-index.js +3 -1
- package/src/create-term-relations.js +3 -1
- package/src/fix-markdown-files.js +2 -1
- package/src/prepare-tref.js +2 -1
- package/src/utils/file-filter.js +36 -0
- package/src/utils/isLineWithDefinition.js +5 -10
- package/readme.md +0 -10
- package/src/collectExternalReferences/checkRateLimit.js +0 -17
- package/src/collectExternalReferences/setupFetchHeaders.js +0 -14
|
@@ -97,7 +97,7 @@ function insertTrefs(allXTrefs) { // Pass allXTrefs as a parameter
|
|
|
97
97
|
|
|
98
98
|
// Clean up markdown content
|
|
99
99
|
let content = xref.content
|
|
100
|
-
.replace(/\[\[def:
|
|
100
|
+
.replace(/\[\[def:[^\]]*?\]\]/g, '') // Remove [[def: ...]] patterns regardless of trailing chars
|
|
101
101
|
.split('\n')
|
|
102
102
|
.map(line => line.replace(/^\s*~\s*/, '')) // Remove leading ~ and spaces
|
|
103
103
|
.join('\n')
|
package/branches.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Beschrijving van de branches
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## dev
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## master
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## test/downloadwholerepo
|
|
15
|
+
|
|
16
|
+
Hierbij wordt de hele repository gedownload. Dit is een experiment om te kijken of ik de hele repository kan downloaden en dan de bestanden kan gebruiken die ik nodig heb. In plaats van de search API te gebruiken met zijn strakke limieten.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## test/fixtref
|
|
20
|
+
|
|
21
|
+
Bewaren, maar kan weg als ik uiteindelijk een andere oplossing heb gevonden.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## test/xtrefnew
|
|
25
|
+
|
|
26
|
+
Lokaal Bewaren
|
|
27
|
+
Lijkt goed te werken.
|
|
28
|
+
Met AI gebouwde oplossing waarbij ik probeer iets aan de API limieten te doen. Ik heb twee belangrijke bestanden weggedaan en AI ze opnieuw laten bouwen op basis van een prompt en de bestanden die ik had. Het lijkt te werken, maar ik heb geen idee of het goed is. Het is een beetje een experiment.
|
|
29
|
+
|
|
30
|
+
## archive/master-pre-bootstrap
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## archive/master-pre-clientside-tref-insertion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-up-t",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.53",
|
|
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": {
|
|
@@ -65,5 +65,11 @@
|
|
|
65
65
|
},
|
|
66
66
|
"overrides": {
|
|
67
67
|
"braces": ">=3.0.3"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"jest": "^29.7.0"
|
|
71
|
+
},
|
|
72
|
+
"scripts": {
|
|
73
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
|
|
68
74
|
}
|
|
69
75
|
}
|
package/src/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<h1>Spec-Up-T External References Collection Workflow</h1>
|
|
2
|
+
<p>This codebase implements a system for collecting and processing cross-specification references from markdown files. Here's a workflow diagram of what happens when <a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#37%2C10" data-keybinding-context="1187"><span class="icon-label">collectExternalReferences()</span></a> is called:</p>
|
|
3
|
+
<h2>Workflow Overview</h2>
|
|
4
|
+
<ol>
|
|
5
|
+
<li>
|
|
6
|
+
<p><strong>Initialization & Configuration</strong></p>
|
|
7
|
+
<ul>
|
|
8
|
+
<li>Loads environment variables using dotenv</li>
|
|
9
|
+
<li>Reads <a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#42%2C39" data-keybinding-context="1188"><span class="icon-label">specs.json</span></a> configuration file</li>
|
|
10
|
+
<li>Obtains GitHub Personal Access Token (PAT) from options or environment variables</li>
|
|
11
|
+
</ul>
|
|
12
|
+
</li>
|
|
13
|
+
<li>
|
|
14
|
+
<p><strong>Validation Checks</strong></p>
|
|
15
|
+
<ul>
|
|
16
|
+
<li>Verifies GitHub PAT is available, stops with instructions if missing</li>
|
|
17
|
+
<li>Confirms external repositories are configured in specs.json</li>
|
|
18
|
+
<li>Validates repository URLs using <a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/utils/doesUrlExist.js#8%2C16" data-keybinding-context="1189"><span class="icon-label">doesUrlExist.js</span></a></li>
|
|
19
|
+
</ul>
|
|
20
|
+
</li>
|
|
21
|
+
<li>
|
|
22
|
+
<p><strong>Content Collection</strong></p>
|
|
23
|
+
<ul>
|
|
24
|
+
<li>Creates necessary output directories</li>
|
|
25
|
+
<li>Reads all markdown files from specified term directories</li>
|
|
26
|
+
<li>Concatenates content into a single string for processing</li>
|
|
27
|
+
</ul>
|
|
28
|
+
</li>
|
|
29
|
+
<li>
|
|
30
|
+
<p><strong>Cross-Reference Extraction</strong></p>
|
|
31
|
+
<ul>
|
|
32
|
+
<li>Uses regex to find <code>[[xref:...]]</code> and <code>[[tref:...]]</code> patterns in markdown</li>
|
|
33
|
+
<li>Processes these patterns into structured objects with <a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#158%2C58" data-keybinding-context="1190"><span class="icon-label">externalSpec</span></a> and <a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#186%2C64" data-keybinding-context="1191"><span class="icon-label">term</span></a> properties</li>
|
|
34
|
+
<li>Filters out duplicates and keeps only references found in current markdown content</li>
|
|
35
|
+
</ul>
|
|
36
|
+
</li>
|
|
37
|
+
<li>
|
|
38
|
+
<p><strong>Metadata Enhancement</strong></p>
|
|
39
|
+
<ul>
|
|
40
|
+
<li>Extends each reference with additional repository information:
|
|
41
|
+
<ul>
|
|
42
|
+
<li>Repository URL</li>
|
|
43
|
+
<li>Owner/repo names</li>
|
|
44
|
+
<li>Terms directory path</li>
|
|
45
|
+
<li>Avatar URL</li>
|
|
46
|
+
</ul>
|
|
47
|
+
</li>
|
|
48
|
+
</ul>
|
|
49
|
+
</li>
|
|
50
|
+
<li>
|
|
51
|
+
<p><strong>GitHub API Interaction</strong></p>
|
|
52
|
+
<ul>
|
|
53
|
+
<li>For each reference, calls <a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collectExternalReferences/fetchTermsFromGitHubRepository.js#16%2C16" data-keybinding-context="1192"><span class="icon-label">fetchTermsFromGitHubRepository</span></a> which:
|
|
54
|
+
<ul>
|
|
55
|
+
<li>Uses Octokit to interface with GitHub API</li>
|
|
56
|
+
<li>Implements caching to minimize API requests</li>
|
|
57
|
+
<li>Handles rate limiting with throttling and retries</li>
|
|
58
|
+
<li>Searches for terms within specified repositories/directories</li>
|
|
59
|
+
</ul>
|
|
60
|
+
</li>
|
|
61
|
+
</ul>
|
|
62
|
+
</li>
|
|
63
|
+
<li>
|
|
64
|
+
<p><strong>Term Content Processing</strong></p>
|
|
65
|
+
<ul>
|
|
66
|
+
<li>When terms are found, retrieves:
|
|
67
|
+
<ul>
|
|
68
|
+
<li>File content</li>
|
|
69
|
+
<li>Latest commit hash</li>
|
|
70
|
+
<li>Repository metadata</li>
|
|
71
|
+
</ul>
|
|
72
|
+
</li>
|
|
73
|
+
<li>Uses <a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collectExternalReferences/matchTerm.js#3%2C10" data-keybinding-context="1193"><span class="icon-label">matchTerm.js</span></a> to validate the term within content</li>
|
|
74
|
+
</ul>
|
|
75
|
+
</li>
|
|
76
|
+
<li>
|
|
77
|
+
<p><strong>Output Generation</strong></p>
|
|
78
|
+
<ul>
|
|
79
|
+
<li>Creates three output files:
|
|
80
|
+
<ul>
|
|
81
|
+
<li><code>output/xtrefs-data.json</code> - JSON data file</li>
|
|
82
|
+
<li><code>output/xtrefs-data.js</code> - JavaScript module file</li>
|
|
83
|
+
<li><code>output/xtrefs-history/xtrefs-data-[timestamp].js</code> - Historical record</li>
|
|
84
|
+
</ul>
|
|
85
|
+
</li>
|
|
86
|
+
</ul>
|
|
87
|
+
</li>
|
|
88
|
+
</ol>
|
|
89
|
+
<h2>Key Functions</h2>
|
|
90
|
+
<ul>
|
|
91
|
+
<li><a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#37%2C10" data-keybinding-context="1194"><span class="icon-label">collectExternalReferences()</span></a>: Main orchestration function</li>
|
|
92
|
+
<li><a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#143%2C18" data-keybinding-context="1195"><span class="icon-label">extendXTrefs()</span></a>: Adds repository metadata to references</li>
|
|
93
|
+
<li><a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#192%2C18" data-keybinding-context="1196"><span class="icon-label">processXTref()</span></a>: Parses reference syntax into structured objects</li>
|
|
94
|
+
<li><a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collect-external-references.js#184%2C18" data-keybinding-context="1197"><span class="icon-label">isXTrefInMarkdown()</span></a>: Validates references against current content</li>
|
|
95
|
+
<li><a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collectExternalReferences/fetchTermsFromGitHubRepository.js#16%2C16" data-keybinding-context="1198"><span class="icon-label">fetchTermsFromGitHubRepository()</span></a>: Interacts with GitHub API to find terms</li>
|
|
96
|
+
<li><a class="chat-inline-anchor-widget show-file-icons" title="" draggable="true" href="vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html" data-href="file:///Users/kor/webdev/Blockchain-Bird/KERI/Spec-Up/active-bcb/spec-up-t/spec-up-t/src/collectExternalReferences/processXTrefsData.js#9%2C16" data-keybinding-context="1199"><span class="icon-label">processXTrefsData()</span></a>: Processes the data and generates output files</li>
|
|
97
|
+
</ul>
|
|
98
|
+
<p>This system enables cross-specification linking by fetching and maintaining references to terms defined in external GitHub repositories, ensuring that documentation can link to canonical definitions maintained elsewhere.</p>
|
|
@@ -1,16 +1,109 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file
|
|
2
|
+
* @file Collects and processes external reference information for cross-specification linking.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* This script fetches the latest commit hash of term files from GitHub repositories
|
|
5
|
+
* configured in specs.json, then generates both JavaScript and JSON files containing
|
|
6
|
+
* cross-reference (xref/tref) data for use in specifications.
|
|
7
|
+
*
|
|
8
|
+
* Example of the output:
|
|
9
|
+
*
|
|
10
|
+
* const allXTrefs = {
|
|
11
|
+
"xtrefs": [
|
|
12
|
+
{
|
|
13
|
+
"externalSpec": "toip1",
|
|
14
|
+
"term": "SSI",
|
|
15
|
+
"repoUrl": "https://github.com/henkvancann/ctwg-main-glossary",
|
|
16
|
+
"terms_dir": "spec/terms-definitions",
|
|
17
|
+
"owner": "henkvancann",
|
|
18
|
+
"repo": "ctwg-main-glossary",
|
|
19
|
+
"site": null,
|
|
20
|
+
"commitHash": "not found",
|
|
21
|
+
"content": "This term was not found in the external repository."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"externalSpec": "vlei1",
|
|
25
|
+
"term": "vlei-ecosystem-governance-framework",
|
|
26
|
+
"repoUrl": "https://github.com/henkvancann/vlei-glossary",
|
|
27
|
+
"terms_dir": "spec/terms-definitions",
|
|
28
|
+
"owner": "henkvancann",
|
|
29
|
+
"repo": "vlei-glossary",
|
|
30
|
+
"avatarUrl": "https://avatars.githubusercontent.com/u/479356?v=4",
|
|
31
|
+
"site": null,
|
|
32
|
+
"commitHash": "5e36b16e58984eeaccae22116a2bf058ab01a0e9",
|
|
33
|
+
"content": "[[def: vlei-ecosystem-governance-framework, vlei ecosystem governance framework]]\n\n~ The Verifiable LEI (vLEI) Ecosystem [[ref: governance-framework]] Information Trust Policies. It's a **document** that defines the … etc"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
};
|
|
5
37
|
*
|
|
6
|
-
* Additionally, the data is written to a JSON file for further processing or usage. This ensures that the xref data is available in both JavaScript and JSON formats, providing flexibility for different use cases.
|
|
7
|
-
*
|
|
8
38
|
* @author Kor Dwarshuis
|
|
9
39
|
* @version 1.0.0
|
|
10
40
|
* @since 2024-06-09
|
|
11
41
|
*/
|
|
12
42
|
|
|
13
43
|
|
|
44
|
+
const { shouldProcessFile } = require('./utils/file-filter');
|
|
45
|
+
function isXTrefInMarkdown(xtref, markdownContent) {
|
|
46
|
+
const regex = new RegExp(`\\[\\[(?:x|t)ref:${xtref.externalSpec},\\s*${xtref.term}\\]\\]`, 'g');
|
|
47
|
+
return regex.test(markdownContent);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Helper function to process an XTref string and return an object.
|
|
51
|
+
function processXTref(xtref) {
|
|
52
|
+
let [externalSpec, term] = xtref
|
|
53
|
+
.replace(/\[\[(?:xref|tref):/, '')
|
|
54
|
+
.replace(/\]\]/, '')
|
|
55
|
+
.trim()
|
|
56
|
+
.split(/,/, 2);
|
|
57
|
+
return {
|
|
58
|
+
externalSpec: externalSpec.trim(),
|
|
59
|
+
term: term.trim()
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
// allMarkdownContent: (string) The content to search for XTrefs.
|
|
65
|
+
// allXTrefs: (object) An object with an array property "xtrefs" to which new entries will be added.
|
|
66
|
+
function addNewXTrefsFromMarkdown(allMarkdownContent, allXTrefs) {
|
|
67
|
+
const regex = /\[\[(?:xref|tref):.*?\]\]/g;
|
|
68
|
+
if (regex.test(allMarkdownContent)) {
|
|
69
|
+
const xtrefs = allMarkdownContent.match(regex);
|
|
70
|
+
xtrefs.forEach(xtref => {
|
|
71
|
+
const newXTrefObj = processXTref(xtref);
|
|
72
|
+
// Add newXTrefObj only if an object with the same term and externalSpec doesn't already exist.
|
|
73
|
+
if (!allXTrefs.xtrefs.some(existingXTref =>
|
|
74
|
+
existingXTref.term === newXTrefObj.term &&
|
|
75
|
+
existingXTref.externalSpec === newXTrefObj.externalSpec)) {
|
|
76
|
+
allXTrefs.xtrefs.push(newXTrefObj);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return allXTrefs;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Collects external references from markdown files and processes them into usable data files.
|
|
85
|
+
*
|
|
86
|
+
* @function collectExternalReferences
|
|
87
|
+
* @param {Object} options - Configuration options
|
|
88
|
+
* @param {string} [options.pat] - GitHub Personal Access Token (overrides environment variable)
|
|
89
|
+
* @returns {void}
|
|
90
|
+
*
|
|
91
|
+
* @description
|
|
92
|
+
* This function performs several key operations:
|
|
93
|
+
* 1. Validates GitHub PAT availability and external repository configurations
|
|
94
|
+
* 2. Checks validity of repository URLs
|
|
95
|
+
* 3. Extracts xref/tref patterns from markdown content
|
|
96
|
+
* 4. Extends references with repository metadata
|
|
97
|
+
* 5. Processes references to fetch commit information
|
|
98
|
+
* 6. Generates output files in both JS and JSON formats
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // Basic usage
|
|
102
|
+
* collectExternalReferences();
|
|
103
|
+
*
|
|
104
|
+
* // With explicit PAT
|
|
105
|
+
* collectExternalReferences({ pat: 'github_pat_xxxxxxxxxxxx' });
|
|
106
|
+
*/
|
|
14
107
|
function collectExternalReferences(options = {}) {
|
|
15
108
|
require('dotenv').config();
|
|
16
109
|
const fs = require('fs-extra');
|
|
@@ -157,21 +250,16 @@ function collectExternalReferences(options = {}) {
|
|
|
157
250
|
});
|
|
158
251
|
}
|
|
159
252
|
|
|
160
|
-
// Function to check if an xtref is in the markdown content
|
|
161
|
-
function isXTrefInMarkdown(xtref, markdownContent) {
|
|
162
|
-
// const regex = new RegExp(`\\[\\[xref:${xref.term}\\]\\]`, 'g');
|
|
163
|
-
const regex = new RegExp(`\\[\\[(?:x|t)ref:${xtref.term}\\]\\]`, 'g');
|
|
164
|
-
const result = regex.test(markdownContent);
|
|
165
|
-
return result;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
253
|
// Function to process and clean up xref / tref strings found in the markdown file, returning an object with `externalSpec` and `term` properties.
|
|
254
|
+
//TODO: check if this is correct
|
|
169
255
|
function processXTref(xtref) {
|
|
170
256
|
let [externalSpec, term] = xtref.replace(/\[\[(?:xref|tref):/, '').replace(/\]\]/, '').trim().split(/,/, 2);
|
|
171
|
-
|
|
257
|
+
const xtrefObject = {
|
|
172
258
|
externalSpec: externalSpec.trim(),
|
|
173
259
|
term: term.trim()
|
|
174
260
|
};
|
|
261
|
+
|
|
262
|
+
return xtrefObject;
|
|
175
263
|
}
|
|
176
264
|
|
|
177
265
|
// Initialize an object to store all xtrefs.
|
|
@@ -191,7 +279,7 @@ function collectExternalReferences(options = {}) {
|
|
|
191
279
|
// Read all main repo Markdown files from a list of directories and concatenate their content into a single string.
|
|
192
280
|
specTermsDirectories.forEach(specDirectory => {
|
|
193
281
|
fs.readdirSync(specDirectory).forEach(file => {
|
|
194
|
-
if (file
|
|
282
|
+
if (shouldProcessFile(file)) {
|
|
195
283
|
const markdown = fs.readFileSync(`${specDirectory}/${file}`, 'utf8');
|
|
196
284
|
allMarkdownContent += markdown;
|
|
197
285
|
}
|
|
@@ -203,21 +291,7 @@ function collectExternalReferences(options = {}) {
|
|
|
203
291
|
return isXTrefInMarkdown(existingXTref, allMarkdownContent);
|
|
204
292
|
});
|
|
205
293
|
|
|
206
|
-
|
|
207
|
-
const regex = /\[\[(?:xref|tref):.*?\]\]/g;
|
|
208
|
-
|
|
209
|
-
// `regex` is the regular expression object, and `allMarkdownContent` is the string being tested. The test method returns a boolean value: true if the pattern is found within the string, and false otherwise.
|
|
210
|
-
if (regex.test(allMarkdownContent)) {
|
|
211
|
-
const xtrefs = allMarkdownContent.match(regex);
|
|
212
|
-
xtrefs.forEach(xtref => {
|
|
213
|
-
const newXTrefObj = processXTref(xtref);
|
|
214
|
-
// Ensure that newXTrefObj is only added to the xtrefs array if there isn't already an object with the same term and externalSpec properties. This helps maintain the uniqueness of entries in the array based on these two properties.
|
|
215
|
-
if (!allXTrefs.xtrefs.some(existingXTref =>
|
|
216
|
-
existingXTref.term === newXTrefObj.term && existingXTref.externalSpec === newXTrefObj.externalSpec)) {
|
|
217
|
-
allXTrefs.xtrefs.push(newXTrefObj);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
};
|
|
294
|
+
addNewXTrefsFromMarkdown(allMarkdownContent, allXTrefs);
|
|
221
295
|
|
|
222
296
|
// Example at this point:
|
|
223
297
|
// allXTrefs.xtrefs: [
|
|
@@ -249,5 +323,8 @@ function collectExternalReferences(options = {}) {
|
|
|
249
323
|
}
|
|
250
324
|
|
|
251
325
|
module.exports = {
|
|
252
|
-
collectExternalReferences
|
|
253
|
-
|
|
326
|
+
collectExternalReferences,
|
|
327
|
+
isXTrefInMarkdown,
|
|
328
|
+
addNewXTrefsFromMarkdown,
|
|
329
|
+
processXTref
|
|
330
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
describe('isXTrefInMarkdown function', () => {
|
|
2
|
+
const isXTrefInMarkdown = require('./collect-external-references').isXTrefInMarkdown;
|
|
3
|
+
|
|
4
|
+
const testCases = [
|
|
5
|
+
{
|
|
6
|
+
name: 'basic xref format',
|
|
7
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
8
|
+
markdown: '[[xref:kmg-1,authentic-chained-data-container]]',
|
|
9
|
+
shouldMatch: true
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
name: 'basic tref format',
|
|
13
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
14
|
+
markdown: '[[tref:kmg-1,authentic-chained-data-container]]',
|
|
15
|
+
shouldMatch: true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'xref with spaces',
|
|
19
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
20
|
+
markdown: '[[xref:kmg-1, authentic-chained-data-container]]',
|
|
21
|
+
shouldMatch: true
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'multiple references in content',
|
|
25
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
26
|
+
markdown: 'Text before [[xref:kmg-1,authentic-chained-data-container]] and text after',
|
|
27
|
+
shouldMatch: true
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'non-matching external spec',
|
|
31
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
32
|
+
markdown: '[[xref:different-spec,authentic-chained-data-container]]',
|
|
33
|
+
shouldMatch: false
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'non-matching term',
|
|
37
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
38
|
+
markdown: '[[xref:kmg-1,different-term]]',
|
|
39
|
+
shouldMatch: false
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'complex term with hyphens',
|
|
43
|
+
xtref: { externalSpec: 'vlei-1', term: 'legal-entity-identifier' },
|
|
44
|
+
markdown: '[[xref:vlei-1,legal-entity-identifier]]',
|
|
45
|
+
shouldMatch: true
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Test cases for case sensitivity
|
|
49
|
+
{
|
|
50
|
+
name: 'uppercase in externalSpec',
|
|
51
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
52
|
+
markdown: '[[xref:KMG-1,authentic-chained-data-container]]',
|
|
53
|
+
shouldMatch: false
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'uppercase in term',
|
|
57
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
58
|
+
markdown: '[[xref:kmg-1,Authentic-Chained-Data-Container]]',
|
|
59
|
+
shouldMatch: false
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'exact case match with mixed case',
|
|
63
|
+
xtref: { externalSpec: 'Mixed-Case', term: 'Some-Mixed-Case-Term' },
|
|
64
|
+
markdown: '[[xref:Mixed-Case,Some-Mixed-Case-Term]]',
|
|
65
|
+
shouldMatch: true
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
The test case below verifies that:
|
|
70
|
+
|
|
71
|
+
- References can be found in a complex, multi-line document
|
|
72
|
+
- The function correctly matches when the reference appears in different parts of the document
|
|
73
|
+
- Both xref and tref formats are properly detected
|
|
74
|
+
- Line breaks and markdown formatting don't interfere with the matching
|
|
75
|
+
|
|
76
|
+
*/
|
|
77
|
+
{
|
|
78
|
+
name: 'multi-line markdown document',
|
|
79
|
+
xtref: { externalSpec: 'kmg-1', term: 'authentic-chained-data-container' },
|
|
80
|
+
markdown: `# Document Title
|
|
81
|
+
|
|
82
|
+
This is a paragraph that talks about various concepts.
|
|
83
|
+
|
|
84
|
+
## First Section
|
|
85
|
+
Here we discuss the [[xref:kmg-1,authentic-chained-data-container]] concept.
|
|
86
|
+
|
|
87
|
+
## Second Section
|
|
88
|
+
This section refers to a different term.
|
|
89
|
+
|
|
90
|
+
## Third Section
|
|
91
|
+
And here we reference it again using [[tref:kmg-1,authentic-chained-data-container]].
|
|
92
|
+
|
|
93
|
+
### Conclusion
|
|
94
|
+
That's all about these references.`,
|
|
95
|
+
shouldMatch: true
|
|
96
|
+
}
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
testCases.forEach(testCase => {
|
|
100
|
+
test(`${testCase.shouldMatch ? 'matches' : 'does not match'} ${testCase.name}`, () => {
|
|
101
|
+
expect(isXTrefInMarkdown(testCase.xtref, testCase.markdown)).toBe(testCase.shouldMatch);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
describe('addNewXTrefsFromMarkdown', () => {
|
|
108
|
+
const addNewXTrefsFromMarkdown = require('./collect-external-references').addNewXTrefsFromMarkdown;
|
|
109
|
+
|
|
110
|
+
it('should add a new xtref from markdown content', () => {
|
|
111
|
+
const markdownContent = "Some text [[xref:specA, termA]] more text";
|
|
112
|
+
const allXTrefs = { xtrefs: [] };
|
|
113
|
+
const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
|
|
114
|
+
|
|
115
|
+
expect(updatedXTrefs.xtrefs.length).toBe(1);
|
|
116
|
+
expect(updatedXTrefs.xtrefs[0]).toEqual({
|
|
117
|
+
externalSpec: 'specA',
|
|
118
|
+
term: 'termA'
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should not add duplicate xtrefs', () => {
|
|
123
|
+
const markdownContent = "Content [[xref:specA, termA]] and again [[xref:specA, termA]]";
|
|
124
|
+
const allXTrefs = { xtrefs: [] };
|
|
125
|
+
const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
|
|
126
|
+
|
|
127
|
+
expect(updatedXTrefs.xtrefs.length).toBe(1);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should add multiple distinct xtrefs', () => {
|
|
131
|
+
const markdownContent = "[[xref:specA, termA]] some text [[tref:specB, termB]]";
|
|
132
|
+
const allXTrefs = { xtrefs: [] };
|
|
133
|
+
const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, allXTrefs);
|
|
134
|
+
|
|
135
|
+
expect(updatedXTrefs.xtrefs.length).toBe(2);
|
|
136
|
+
expect(updatedXTrefs.xtrefs).toEqual(
|
|
137
|
+
expect.arrayContaining([
|
|
138
|
+
{ externalSpec: 'specA', term: 'termA' },
|
|
139
|
+
{ externalSpec: 'specB', term: 'termB' }
|
|
140
|
+
])
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should not change xtrefs when no xtrefs are found in markdown content', () => {
|
|
145
|
+
const markdownContent = "This is markdown without any reference links.";
|
|
146
|
+
const initialXTrefs = { xtrefs: [] };
|
|
147
|
+
const updatedXTrefs = addNewXTrefsFromMarkdown(markdownContent, initialXTrefs);
|
|
148
|
+
|
|
149
|
+
expect(updatedXTrefs.xtrefs.length).toBe(0);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
});
|
|
@@ -3,6 +3,8 @@ const path = require('path');
|
|
|
3
3
|
const crypto = require('crypto'); // For generating cache keys
|
|
4
4
|
const isLineWithDefinition = require('../utils/isLineWithDefinition').isLineWithDefinition;
|
|
5
5
|
const { addPath, getPath, getAllPaths } = require('../config/paths');
|
|
6
|
+
const { getSearchClient, getContentClient } = require('./octokitClient');
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
// Directory to store cached files
|
|
8
10
|
const CACHE_DIR = getPath('githubcache');
|
|
@@ -13,36 +15,21 @@ function generateCacheKey(...args) {
|
|
|
13
15
|
return hash;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
async function fetchTermsFromGitHubRepository(GITHUB_API_TOKEN, searchString, owner, repo, subdirectory) {
|
|
17
|
-
const { Octokit } = await import("octokit");
|
|
18
|
-
const { throttling } = await import("@octokit/plugin-throttling");
|
|
19
|
-
|
|
20
|
-
// Create a throttled Octokit instance
|
|
21
|
-
const ThrottledOctokit = Octokit.plugin(throttling);
|
|
22
|
-
const octokit = new ThrottledOctokit({
|
|
23
|
-
auth: GITHUB_API_TOKEN,
|
|
24
|
-
throttle: {
|
|
25
|
-
onRateLimit: (retryAfter, options) => {
|
|
26
|
-
console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
|
|
27
|
-
if (options.request.retryCount <= 1) {
|
|
28
|
-
console.log(`Retrying after ${retryAfter} seconds...`);
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
onAbuseLimit: (retryAfter, options) => {
|
|
33
|
-
console.warn(`Abuse detected for request ${options.method} ${options.url}`);
|
|
34
|
-
},
|
|
35
|
-
onSecondaryRateLimit: (retryAfter, options) => {
|
|
36
|
-
console.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`);
|
|
37
|
-
if (options.request.retryCount <= 1) {
|
|
38
|
-
console.log(`Retrying after ${retryAfter} seconds...`);
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
18
|
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async function fetchTermsFromGitHubRepository(GITHUB_API_TOKEN, searchString, owner, repo, subdirectory) {
|
|
26
|
+
console.log(`Searching for '${searchString}' in ${owner}/${repo}/${subdirectory}`);
|
|
45
27
|
try {
|
|
28
|
+
// Create directory if it doesn't exist
|
|
29
|
+
if (!fs.existsSync(CACHE_DIR)) {
|
|
30
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
46
33
|
// Generate a cache key for the search query
|
|
47
34
|
const searchCacheKey = generateCacheKey('search', searchString, owner, repo, subdirectory);
|
|
48
35
|
const searchCacheFilePath = path.join(CACHE_DIR, `${searchCacheKey}.json`);
|
|
@@ -54,21 +41,22 @@ async function fetchTermsFromGitHubRepository(GITHUB_API_TOKEN, searchString, ow
|
|
|
54
41
|
console.log(`Serving search results from cache: ${searchCacheFilePath}`);
|
|
55
42
|
searchResponse = JSON.parse(fs.readFileSync(searchCacheFilePath, 'utf-8'));
|
|
56
43
|
} else {
|
|
57
|
-
//
|
|
44
|
+
// Get the search client
|
|
58
45
|
console.log(`Performing search and caching results: ${searchCacheFilePath}`);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
},
|
|
64
|
-
});
|
|
46
|
+
const searchClient = await getSearchClient(GITHUB_API_TOKEN);
|
|
47
|
+
|
|
48
|
+
// Perform the search
|
|
49
|
+
searchResponse = await searchClient.search(searchString, owner, repo, subdirectory);
|
|
65
50
|
|
|
66
51
|
// Cache the search response
|
|
67
52
|
fs.writeFileSync(searchCacheFilePath, JSON.stringify(searchResponse), 'utf-8');
|
|
68
53
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
54
|
+
// After search
|
|
55
|
+
console.log(`Search found ${searchResponse.data.total_count} results`);
|
|
56
|
+
if (searchResponse.data.total_count === 0) {
|
|
57
|
+
console.log("No matches found - check if term exists in repository");
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
72
60
|
|
|
73
61
|
/*
|
|
74
62
|
|
|
@@ -195,11 +183,12 @@ async function fetchTermsFromGitHubRepository(GITHUB_API_TOKEN, searchString, ow
|
|
|
195
183
|
// Fetch file content from GitHub
|
|
196
184
|
console.log(`Downloading and caching file: ${fileCacheFilePath}`);
|
|
197
185
|
try {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
186
|
+
const contentClient = await getContentClient(GITHUB_API_TOKEN);
|
|
187
|
+
const fileContentResponse = await contentClient.getContent(
|
|
188
|
+
item.repository.owner.login,
|
|
189
|
+
item.repository.name,
|
|
190
|
+
item.path
|
|
191
|
+
);
|
|
203
192
|
|
|
204
193
|
// Decode the file content (it's base64-encoded)
|
|
205
194
|
if (fileContentResponse.data.content) {
|
|
@@ -227,7 +216,13 @@ async function fetchTermsFromGitHubRepository(GITHUB_API_TOKEN, searchString, ow
|
|
|
227
216
|
}
|
|
228
217
|
}
|
|
229
218
|
} catch (error) {
|
|
230
|
-
console.error("Error
|
|
219
|
+
console.error("Error details:", {
|
|
220
|
+
message: error.message,
|
|
221
|
+
status: error.status,
|
|
222
|
+
type: error.constructor.name,
|
|
223
|
+
details: error.response?.data?.message || "No additional details"
|
|
224
|
+
});
|
|
225
|
+
return null;
|
|
231
226
|
}
|
|
232
227
|
|
|
233
228
|
// If no item is found, return null or undefined
|