spec-up-t 1.0.73 → 1.0.75
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/index.spec-up.js +366 -0
- package/package.json +1 -1
- package/src/get-xrefs-data.js +12 -97
- package/src/prepare-tref.js +7 -0
package/index.spec-up.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
|
|
2
|
+
module.exports = function (options = {}) {
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
fetchExternalSpecs,
|
|
6
|
+
validateReferences,
|
|
7
|
+
findExternalSpecByKey
|
|
8
|
+
} = require('./references.js');
|
|
9
|
+
const gulp = require('gulp');
|
|
10
|
+
const fs = require('fs-extra');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const findPkgDir = require('find-pkg-dir');
|
|
13
|
+
const modulePath = findPkgDir(__dirname);
|
|
14
|
+
let config = fs.readJsonSync('./specs.json');
|
|
15
|
+
let assets = fs.readJsonSync(modulePath + '/src/asset-map.json');
|
|
16
|
+
let externalReferences;
|
|
17
|
+
let references = [];
|
|
18
|
+
let definitions = [];
|
|
19
|
+
|
|
20
|
+
const katexRules = ['math_block', 'math_inline']
|
|
21
|
+
const replacerRegex = /\[\[\s*([^\s\[\]:]+):?\s*([^\]\n]+)?\]\]/img;
|
|
22
|
+
const replacerArgsRegex = /\s*,+\s*/;
|
|
23
|
+
const replacers = [
|
|
24
|
+
{
|
|
25
|
+
test: 'insert',
|
|
26
|
+
transform: function (path) {
|
|
27
|
+
if (!path) return '';
|
|
28
|
+
return fs.readFileSync(path, 'utf8');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
function applyReplacers(doc) {
|
|
34
|
+
return doc.replace(replacerRegex, function (match, type, args) {
|
|
35
|
+
let replacer = replacers.find(r => type.trim().match(r.test));
|
|
36
|
+
return replacer ? replacer.transform(...args.trim().split(replacerArgsRegex)) : match;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function normalizePath(path) {
|
|
41
|
+
return path.trim().replace(/\/$/g, '') + '/';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function renderRefGroup(type) {
|
|
45
|
+
let group = specGroups[type];
|
|
46
|
+
if (!group) return '';
|
|
47
|
+
let html = Object.keys(group).sort().reduce((html, name) => {
|
|
48
|
+
let ref = group[name];
|
|
49
|
+
return html += `
|
|
50
|
+
<dt id="ref:${name}">${name}</dt>
|
|
51
|
+
<dd>
|
|
52
|
+
<cite><a href="${ref.href}">${ref.title}</a></cite>.
|
|
53
|
+
${ref.authors.join('; ')}; ${ref.rawDate}. <span class="reference-status">Status: ${ref.status}</span>.
|
|
54
|
+
</dd>
|
|
55
|
+
`;
|
|
56
|
+
}, '<dl class="reference-list">')
|
|
57
|
+
return `\n${html}\n</dl>\n`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function findKatexDist() {
|
|
61
|
+
const relpath = "node_modules/katex/dist";
|
|
62
|
+
const paths = [
|
|
63
|
+
path.join(process.cwd(), relpath),
|
|
64
|
+
path.join(__dirname, relpath),
|
|
65
|
+
];
|
|
66
|
+
for (const abspath of paths) {
|
|
67
|
+
if (fs.existsSync(abspath)) {
|
|
68
|
+
return abspath
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
throw Error("katex distribution could not be located");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
|
|
76
|
+
var toc;
|
|
77
|
+
var specGroups = {};
|
|
78
|
+
const noticeTypes = {
|
|
79
|
+
note: 1,
|
|
80
|
+
issue: 1,
|
|
81
|
+
example: 1,
|
|
82
|
+
warning: 1,
|
|
83
|
+
todo: 1
|
|
84
|
+
};
|
|
85
|
+
const spaceRegex = /\s+/g;
|
|
86
|
+
const specNameRegex = /^spec$|^spec[-]*\w+$/i;
|
|
87
|
+
const terminologyRegex = /^def$|^ref$|^xref/i;
|
|
88
|
+
const specCorpus = fs.readJsonSync(modulePath + '/assets/compiled/refs.json');
|
|
89
|
+
const containers = require('markdown-it-container');
|
|
90
|
+
const md = require('markdown-it')({
|
|
91
|
+
html: true,
|
|
92
|
+
linkify: true,
|
|
93
|
+
typographer: true
|
|
94
|
+
})
|
|
95
|
+
.use(require('./src/markdown-it-extensions.js'), [
|
|
96
|
+
{
|
|
97
|
+
filter: type => type.match(terminologyRegex),
|
|
98
|
+
parse(token, type, primary) {
|
|
99
|
+
if (!primary) return;
|
|
100
|
+
if (type === 'def') {
|
|
101
|
+
definitions.push(token.info.args);
|
|
102
|
+
return token.info.args.reduce((acc, syn) => {
|
|
103
|
+
return `<span id="term:${syn.replace(spaceRegex, '-').toLowerCase()}">${acc}</span>`;
|
|
104
|
+
}, primary);
|
|
105
|
+
}
|
|
106
|
+
else if (type === 'xref') {
|
|
107
|
+
const url = findExternalSpecByKey(config, token.info.args[0]);
|
|
108
|
+
const term = token.info.args[1].replace(spaceRegex, '-').toLowerCase();
|
|
109
|
+
return `<a class="term-reference" data-local-href="#term:${token.info.args[0]}:${term}"
|
|
110
|
+
href="${url}#term:${term}">${token.info.args[1]}</a>`;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
references.push(primary);
|
|
114
|
+
return `<a class="term-reference" href="#term:${primary.replace(spaceRegex, '-').toLowerCase()}">${primary}</a>`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
filter: type => type.match(specNameRegex),
|
|
120
|
+
parse(token, type, name) {
|
|
121
|
+
if (name) {
|
|
122
|
+
let _name = name.replace(spaceRegex, '-').toUpperCase();
|
|
123
|
+
let spec = specCorpus[_name] ||
|
|
124
|
+
specCorpus[_name.toLowerCase()] ||
|
|
125
|
+
specCorpus[name.toLowerCase()] ||
|
|
126
|
+
specCorpus[name];
|
|
127
|
+
if (spec) {
|
|
128
|
+
spec._name = _name;
|
|
129
|
+
let group = specGroups[type] = specGroups[type] || {};
|
|
130
|
+
token.info.spec = group[_name] = spec;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
render(token, type, name) {
|
|
135
|
+
if (name) {
|
|
136
|
+
let spec = token.info.spec;
|
|
137
|
+
if (spec) return `[<a class="spec-reference" href="#ref:${spec._name}">${spec._name}</a>]`;
|
|
138
|
+
}
|
|
139
|
+
else return renderRefGroup(type);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
])
|
|
143
|
+
.use(require('markdown-it-attrs'))
|
|
144
|
+
.use(require('markdown-it-chart').default)
|
|
145
|
+
.use(require('markdown-it-deflist'))
|
|
146
|
+
.use(require('markdown-it-references'))
|
|
147
|
+
.use(require('markdown-it-icons').default, 'font-awesome')
|
|
148
|
+
.use(require('markdown-it-ins'))
|
|
149
|
+
.use(require('markdown-it-mark'))
|
|
150
|
+
.use(require('markdown-it-textual-uml'))
|
|
151
|
+
.use(require('markdown-it-sub'))
|
|
152
|
+
.use(require('markdown-it-sup'))
|
|
153
|
+
.use(require('markdown-it-task-lists'))
|
|
154
|
+
.use(require('markdown-it-multimd-table'), {
|
|
155
|
+
multiline: true,
|
|
156
|
+
rowspan: true,
|
|
157
|
+
headerless: true
|
|
158
|
+
})
|
|
159
|
+
.use(containers, 'notice', {
|
|
160
|
+
validate: function (params) {
|
|
161
|
+
let matches = params.match(/(\w+)\s?(.*)?/);
|
|
162
|
+
return matches && noticeTypes[matches[1]];
|
|
163
|
+
},
|
|
164
|
+
render: function (tokens, idx) {
|
|
165
|
+
let matches = tokens[idx].info.match(/(\w+)\s?(.*)?/);
|
|
166
|
+
if (matches && tokens[idx].nesting === 1) {
|
|
167
|
+
let id;
|
|
168
|
+
let type = matches[1];
|
|
169
|
+
if (matches[2]) {
|
|
170
|
+
id = matches[2].trim().replace(/\s+/g, '-').toLowerCase();
|
|
171
|
+
if (noticeTitles[id]) id += '-' + noticeTitles[id]++;
|
|
172
|
+
else noticeTitles[id] = 1;
|
|
173
|
+
}
|
|
174
|
+
else id = type + '-' + noticeTypes[type]++;
|
|
175
|
+
return `<div id="${id}" class="notice ${type}"><a class="notice-link" href="#${id}">${type.toUpperCase()}</a>`;
|
|
176
|
+
}
|
|
177
|
+
else return '</div>\n';
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
.use(require('markdown-it-prism'))
|
|
181
|
+
.use(require('markdown-it-toc-and-anchor').default, {
|
|
182
|
+
tocClassName: 'toc',
|
|
183
|
+
tocFirstLevel: 2,
|
|
184
|
+
tocLastLevel: 4,
|
|
185
|
+
tocCallback: (_md, _tokens, html) => toc = html,
|
|
186
|
+
anchorLinkSymbol: '§',
|
|
187
|
+
anchorClassName: 'toc-anchor'
|
|
188
|
+
})
|
|
189
|
+
.use(require('@traptitech/markdown-it-katex'))
|
|
190
|
+
|
|
191
|
+
async function render(spec, assets) {
|
|
192
|
+
try {
|
|
193
|
+
noticeTitles = {};
|
|
194
|
+
specGroups = {};
|
|
195
|
+
console.log('Rendering: ' + spec.title);
|
|
196
|
+
return new Promise(async (resolve, reject) => {
|
|
197
|
+
Promise.all((spec.markdown_paths || ['spec.md']).map(_path => {
|
|
198
|
+
return fs.readFile(spec.spec_directory + _path, 'utf8').catch(e => reject(e))
|
|
199
|
+
})).then(async docs => {
|
|
200
|
+
const features = (({ source, logo }) => ({ source, logo }))(spec);
|
|
201
|
+
if (spec.external_specs && !externalReferences) {
|
|
202
|
+
externalReferences = await fetchExternalSpecs(spec);
|
|
203
|
+
}
|
|
204
|
+
let doc = docs.join("\n");
|
|
205
|
+
doc = applyReplacers(doc);
|
|
206
|
+
md[spec.katex ? "enable" : "disable"](katexRules);
|
|
207
|
+
const render = md.render(doc);
|
|
208
|
+
fs.writeFile(path.join(spec.destination, 'index.html'), `
|
|
209
|
+
<!DOCTYPE html>
|
|
210
|
+
<html lang="en">
|
|
211
|
+
<head>
|
|
212
|
+
<meta charset="utf-8">
|
|
213
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
214
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
215
|
+
|
|
216
|
+
<title>${spec.title}</title>
|
|
217
|
+
|
|
218
|
+
<link href="https://fonts.googleapis.com/css2?family=Heebo:wght@300;400&display=swap" rel="stylesheet">
|
|
219
|
+
|
|
220
|
+
${assets.head}
|
|
221
|
+
</head>
|
|
222
|
+
<body features="${Object.keys(features).join(' ')}">
|
|
223
|
+
|
|
224
|
+
${assets.svg}
|
|
225
|
+
|
|
226
|
+
<main>
|
|
227
|
+
|
|
228
|
+
<header id="header" class="panel-header">
|
|
229
|
+
<span id="toc_toggle" panel-toggle="toc">
|
|
230
|
+
<svg icon><use xlink:href="#svg-nested-list"></use></svg>
|
|
231
|
+
</span>
|
|
232
|
+
<a id="logo" href="${spec.logo_link ? spec.logo_link : '#_'}">
|
|
233
|
+
<img src="${spec.logo}" />
|
|
234
|
+
</a>
|
|
235
|
+
<span issue-count animate panel-toggle="repo_issues">
|
|
236
|
+
<svg icon><use xlink:href="#svg-github"></use></svg>
|
|
237
|
+
</span>
|
|
238
|
+
</header>
|
|
239
|
+
|
|
240
|
+
<article id="content">
|
|
241
|
+
${render}
|
|
242
|
+
</article>
|
|
243
|
+
|
|
244
|
+
</main>
|
|
245
|
+
|
|
246
|
+
<slide-panels id="slidepanels">
|
|
247
|
+
<slide-panel id="repo_issues" options="right">
|
|
248
|
+
<header class="panel-header">
|
|
249
|
+
<span>
|
|
250
|
+
<svg icon><use xlink:href="#svg-github"></use></svg>
|
|
251
|
+
<span issue-count></span>
|
|
252
|
+
</span>
|
|
253
|
+
<span class="repo-issue-toggle" panel-toggle="repo_issues">✕</span>
|
|
254
|
+
</header>
|
|
255
|
+
<ul id="repo_issue_list"></ul>
|
|
256
|
+
</slide-panel>
|
|
257
|
+
|
|
258
|
+
<slide-panel id="toc">
|
|
259
|
+
<header class="panel-header">
|
|
260
|
+
<span>Table of Contents</span>
|
|
261
|
+
<span panel-toggle="toc">✕</span>
|
|
262
|
+
</header>
|
|
263
|
+
<div id="toc_list">
|
|
264
|
+
${toc}
|
|
265
|
+
</div>
|
|
266
|
+
</slide-panel>
|
|
267
|
+
|
|
268
|
+
</slide-panels>
|
|
269
|
+
<div style="display: none;">
|
|
270
|
+
${externalReferences}
|
|
271
|
+
</div>
|
|
272
|
+
</body>
|
|
273
|
+
<script>window.specConfig = ${JSON.stringify(spec)}</script>
|
|
274
|
+
${assets.body}
|
|
275
|
+
</html>
|
|
276
|
+
`, function (err, data) {
|
|
277
|
+
if (err) {
|
|
278
|
+
reject(err);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
resolve();
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
validateReferences(references, definitions, render);
|
|
285
|
+
references = [];
|
|
286
|
+
definitions = [];
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
catch (e) {
|
|
291
|
+
console.error(e);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
config.specs.forEach(spec => {
|
|
296
|
+
spec.spec_directory = normalizePath(spec.spec_directory);
|
|
297
|
+
spec.destination = normalizePath(spec.output_path || spec.spec_directory);
|
|
298
|
+
|
|
299
|
+
fs.ensureDirSync(spec.destination);
|
|
300
|
+
|
|
301
|
+
let assetTags = {
|
|
302
|
+
svg: fs.readFileSync(modulePath + '/assets/icons.svg', 'utf8') || ''
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
let customAssets = (spec.assets || []).reduce((assets, asset) => {
|
|
306
|
+
let ext = asset.path.split('.').pop();
|
|
307
|
+
if (ext === 'css') {
|
|
308
|
+
assets.css += `<link href="${asset.path}" rel="stylesheet"/>`;
|
|
309
|
+
}
|
|
310
|
+
if (ext === 'js') {
|
|
311
|
+
assets.js[asset.inject || 'body'] += `<script src="${asset.path}" ${asset.module ? 'type="module"' : ''} ></script>`;
|
|
312
|
+
}
|
|
313
|
+
return assets;
|
|
314
|
+
}, {
|
|
315
|
+
css: '',
|
|
316
|
+
js: { head: '', body: '' }
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
if (options.dev) {
|
|
320
|
+
assetTags.head = assets.head.css.map(_path => `<link href="${_path}" rel="stylesheet"/>`).join('') +
|
|
321
|
+
customAssets.css +
|
|
322
|
+
assets.head.js.map(_path => `<script src="${_path}"></script>`).join('') +
|
|
323
|
+
customAssets.js.head;
|
|
324
|
+
assetTags.body = assets.body.js.map(_path => `<script src="${_path}" data-manual></script>`).join('') +
|
|
325
|
+
customAssets.js.body;
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
assetTags.head = `
|
|
329
|
+
<style>${fs.readFileSync(modulePath + '/assets/compiled/head.css', 'utf8')}</style>
|
|
330
|
+
${customAssets.css}
|
|
331
|
+
<script>${fs.readFileSync(modulePath + '/assets/compiled/head.js', 'utf8')}</script>
|
|
332
|
+
${customAssets.js.head}
|
|
333
|
+
`;
|
|
334
|
+
assetTags.body = `<script>${fs.readFileSync(modulePath + '/assets/compiled/body.js', 'utf8')}</script>
|
|
335
|
+
${customAssets.js.body}`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (spec.katex) {
|
|
339
|
+
const katexDist = findKatexDist();
|
|
340
|
+
assetTags.body += `<script>/* katex */${fs.readFileSync(path.join(katexDist, 'katex.min.js'),
|
|
341
|
+
'utf8')}</script>`;
|
|
342
|
+
assetTags.body += `<style>/* katex */${fs.readFileSync(path.join(katexDist, 'katex.min.css'),
|
|
343
|
+
'utf8')}</style>`;
|
|
344
|
+
|
|
345
|
+
fs.copySync(path.join(katexDist, 'fonts'), path.join(spec.destination, 'fonts'));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (!options.nowatch) {
|
|
349
|
+
gulp.watch(
|
|
350
|
+
[spec.spec_directory + '**/*', '!' + path.join(spec.destination, 'index.html')],
|
|
351
|
+
render.bind(null, spec, assetTags)
|
|
352
|
+
)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
render(spec, assetTags).then(() => {
|
|
356
|
+
if (options.nowatch) process.exit(0)
|
|
357
|
+
}).catch(() => process.exit(1));
|
|
358
|
+
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
catch (e) {
|
|
363
|
+
console.error(e);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-up-t",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.75",
|
|
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": {
|
package/src/get-xrefs-data.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file This
|
|
2
|
+
* @file This script is responsible for fetching the latest commit hash of term files from the GitHub API and generating both a JavaScript file and a JSON file containing the data for the cross-references (xrefs).
|
|
3
|
+
*
|
|
4
|
+
* The generated JavaScript file is included in the HTML output of the specification, serving as a data source for the JavaScript code embedded in the HTML file.
|
|
5
|
+
*
|
|
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
|
+
*
|
|
3
8
|
* @author Kor Dwarshuis
|
|
4
9
|
* @version 1.0.0
|
|
5
10
|
* @since 2024-06-09
|
|
@@ -106,7 +111,7 @@ async function fetchFileContentFromCommit(GITHUB_API_TOKEN, owner, repo, commitH
|
|
|
106
111
|
return null;
|
|
107
112
|
}
|
|
108
113
|
|
|
109
|
-
function updateXrefs(GITHUB_API_TOKEN) {
|
|
114
|
+
function updateXrefs(GITHUB_API_TOKEN, skipExisting) {
|
|
110
115
|
// Function to extend xref objects with additional information, such as repository URL and directory information.
|
|
111
116
|
function extendXrefs(config, xrefs) {
|
|
112
117
|
if (config.specs[0].external_specs_repos) {
|
|
@@ -211,20 +216,19 @@ function updateXrefs(GITHUB_API_TOKEN) {
|
|
|
211
216
|
|
|
212
217
|
It checks if the xref object already has a commitHash and content.If both are present, it skips fetching the term information from GitHub. This ensures that existing commit hashes are not overwritten.
|
|
213
218
|
*/
|
|
214
|
-
async function fetchAllTermsInfoFromGithub() {
|
|
219
|
+
async function fetchAllTermsInfoFromGithub(skipExisting) {
|
|
215
220
|
for (let xref of allXrefs.xrefs) {
|
|
216
|
-
if (!xref.commitHash || !xref.content) {
|
|
221
|
+
if (!skipExisting || (!xref.commitHash || !xref.content)) {
|
|
217
222
|
const fetchedData = await fetchTermInfoFromGithub(GITHUB_API_TOKEN, xref);
|
|
218
223
|
if (fetchedData) {
|
|
219
224
|
xref.commitHash = fetchedData.commitHash;
|
|
220
225
|
xref.content = fetchedData.content;
|
|
221
226
|
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
227
|
+
} }
|
|
224
228
|
}
|
|
225
229
|
|
|
226
230
|
// Fetch all term information, then write the results to JSON and JS files.
|
|
227
|
-
fetchAllTermsInfoFromGithub().then(() => {
|
|
231
|
+
fetchAllTermsInfoFromGithub(skipExisting).then(() => {
|
|
228
232
|
const allXrefsStr = JSON.stringify(allXrefs, null, 2);
|
|
229
233
|
fs.writeFileSync(outputPathJSON, allXrefsStr, 'utf8');
|
|
230
234
|
const stringReadyForFileWrite = `const allXrefs = ${allXrefsStr};`;
|
|
@@ -238,96 +242,7 @@ function updateXrefs(GITHUB_API_TOKEN) {
|
|
|
238
242
|
});
|
|
239
243
|
}
|
|
240
244
|
|
|
241
|
-
// Function to remove a specific xref from the JSON file, based on term and externalSpec.
|
|
242
|
-
function removeXref(term, externalSpec) {
|
|
243
|
-
let messages = [];
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
// Read the JSON file
|
|
247
|
-
let currentXrefs = fs.readJsonSync(outputPathJSON);
|
|
248
|
-
|
|
249
|
-
// Check if the term and externalSpec exist
|
|
250
|
-
const entryExists = currentXrefs.xrefs.some(xref => xref.term === term && xref.externalSpec === externalSpec);
|
|
251
|
-
|
|
252
|
-
if (!entryExists) {
|
|
253
|
-
messages.push(`\n SPEC-UP-T: Entry with term "${term}" and externalSpec "${externalSpec}" not found.\n`);
|
|
254
|
-
return messages;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Remove the entry from the JSON file
|
|
258
|
-
currentXrefs.xrefs = currentXrefs.xrefs.filter(xref => {
|
|
259
|
-
return !(xref.term === term && xref.externalSpec === externalSpec);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// Convert the JSON object back to a JSON string
|
|
263
|
-
const currentXrefsStr = JSON.stringify(currentXrefs, null, 2);
|
|
264
|
-
|
|
265
|
-
// Write the JSON code to a .json file
|
|
266
|
-
fs.writeFileSync(outputPathJSON, currentXrefsStr, 'utf8');
|
|
267
|
-
|
|
268
|
-
// Create the JS code for the assignment
|
|
269
|
-
const stringReadyForFileWrite = `const allXrefs = ${currentXrefsStr};`;
|
|
270
|
-
|
|
271
|
-
// Write the JS code to a .js file
|
|
272
|
-
fs.writeFileSync(outputPathJS, stringReadyForFileWrite, 'utf8');
|
|
273
|
-
|
|
274
|
-
messages.push(`\n SPEC-UP-T: Entry with term "${term}" and externalSpec "${externalSpec}" removed.\n`);
|
|
275
|
-
|
|
276
|
-
// Run the render function to update the HTML file
|
|
277
|
-
require('../index.js')({ nowatch: true });
|
|
278
|
-
|
|
279
|
-
} catch (error) {
|
|
280
|
-
messages.push(`\n SPEC-UP-T: An error occurred - ${error.message}\n`);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// TODO: messages are not used at the moment, since they apparently are not returned to the calling script. Fix this.
|
|
284
|
-
|
|
285
|
-
return messages;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function addXref(term, externalSpec) {
|
|
289
|
-
let messages = [];
|
|
290
|
-
|
|
291
|
-
try {
|
|
292
|
-
// Read the JSON file
|
|
293
|
-
let currentXrefs = fs.readJsonSync(outputPathJSON);
|
|
294
|
-
|
|
295
|
-
// Check if the term and externalSpec exist
|
|
296
|
-
const entryExists = currentXrefs.xrefs.some(xref => xref.term === term && xref.externalSpec === externalSpec);
|
|
297
|
-
|
|
298
|
-
if (entryExists) {
|
|
299
|
-
messages.push(`\n SPEC-UP-T: Entry with term "${term}" and externalSpec "${externalSpec}" already exists.\n`);
|
|
300
|
-
return messages;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Add the entry to the JSON file
|
|
304
|
-
currentXrefs.xrefs.push({ term, externalSpec });
|
|
305
|
-
|
|
306
|
-
// Convert the JSON object back to a JSON string
|
|
307
|
-
const currentXrefsStr = JSON.stringify(currentXrefs, null, 2);
|
|
308
|
-
|
|
309
|
-
// Write the JSON code to a .json file
|
|
310
|
-
fs.writeFileSync(outputPathJSON, currentXrefsStr, 'utf8');
|
|
311
|
-
|
|
312
|
-
// Create the JS code for the assignment
|
|
313
|
-
const stringReadyForFileWrite = `const allXrefs = ${currentXrefsStr};`;
|
|
314
|
-
|
|
315
|
-
// Write the JS code to a .js file
|
|
316
|
-
fs.writeFileSync(outputPathJS, stringReadyForFileWrite, 'utf8');
|
|
317
|
-
|
|
318
|
-
messages.push(`\n SPEC-UP-T: Entry with term "${term}" and externalSpec "${externalSpec}" added.\n`);
|
|
319
|
-
|
|
320
|
-
// Run the render function to update the HTML file
|
|
321
|
-
require('../index.js')({ nowatch: true });
|
|
322
|
-
|
|
323
|
-
} catch (error) {
|
|
324
|
-
messages.push(`\n SPEC-UP-T: An error occurred - ${error.message}\n`);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
245
|
// Export the updateXrefs and removeXref functions for use in other modules.
|
|
329
246
|
module.exports = {
|
|
330
|
-
updateXrefs
|
|
331
|
-
removeXref,
|
|
332
|
-
addXref
|
|
247
|
+
updateXrefs
|
|
333
248
|
}
|