spec-up-t 1.0.88 → 1.0.89
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.js +361 -341
- package/package.json +4 -1
- package/src/config/paths.js +46 -0
- package/src/create-versions-index.js +1 -1
- package/src/fix-markdown-files.js +1 -2
- package/src/get-xtrefs-data/checkRateLimit.js +17 -0
- package/src/get-xtrefs-data/matchTerm.1.js +23 -0
- package/src/get-xtrefs-data/matchTerm.js +26 -0
- package/src/get-xtrefs-data/searchGitHubCode.1.js +69 -0
- package/src/get-xtrefs-data/searchGitHubCode.2.js +77 -0
- package/src/get-xtrefs-data/searchGitHubCode.3.js +85 -0
- package/src/get-xtrefs-data/searchGitHubCode.4.js +92 -0
- package/src/get-xtrefs-data/searchGitHubCode.5.js +97 -0
- package/src/get-xtrefs-data/searchGitHubCode.js +97 -0
- package/src/get-xtrefs-data/setupFetchHeaders.js +14 -0
- package/src/get-xtrefs-data.js +95 -145
- package/src/init.js +36 -0
- package/src/json-key-validator.js +1 -1
- package/src/prepare-tref.js +16 -3
- package/src/utils/doesUrlExist.js +14 -0
package/index.js
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
|
+
const { initialize } = require('./src/init');
|
|
1
2
|
|
|
2
|
-
module.exports = function (options = {}) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
module.exports = async function (options = {}) {
|
|
4
|
+
try {
|
|
5
|
+
// Run the initialization first
|
|
6
|
+
await initialize();
|
|
7
|
+
console.log('Initialization complete. Proceeding with the rest of the module logic...');
|
|
8
|
+
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const gulp = require('gulp');
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
const {
|
|
14
|
+
fetchExternalSpecs,
|
|
15
|
+
validateReferences,
|
|
16
|
+
findExternalSpecByKey
|
|
17
|
+
} = require('./src/references.js');
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
const { runJsonKeyValidatorSync } = require('./src/json-key-validator.js');
|
|
20
|
+
runJsonKeyValidatorSync();
|
|
15
21
|
|
|
16
22
|
// const { createTermRelations } = require('./src/create-term-relations.js');
|
|
17
23
|
// createTermRelations();
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
const { createTermIndex } = require('./src/create-term-index.js');
|
|
26
|
+
createTermIndex();
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
const { insertTermIndex } = require('./src/insert-term-index.js');
|
|
29
|
+
insertTermIndex();
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
const findPkgDir = require('find-pkg-dir');
|
|
32
|
+
const modulePath = findPkgDir(__dirname);
|
|
33
|
+
let config = fs.readJsonSync('./output/specs-generated.json');
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
const createVersionsIndex = require('./src/create-versions-index.js');
|
|
36
|
+
createVersionsIndex(config.specs[0].output_path);
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
const { fixMarkdownFiles } = require('./src/fix-markdown-files.js');
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
const { prepareTref } = require('./src/prepare-tref.js');
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
let template = fs.readFileSync(path.join(modulePath, 'templates/template.html'), 'utf8');
|
|
43
|
+
let assets = fs.readJsonSync(modulePath + '/src/asset-map.json');
|
|
44
|
+
let externalReferences;
|
|
45
|
+
let references = [];
|
|
46
|
+
let definitions = [];
|
|
41
47
|
|
|
42
|
-
const katexRules = ['math_block', 'math_inline']
|
|
48
|
+
const katexRules = ['math_block', 'math_inline'];
|
|
43
49
|
const replacerRegex = /\[\[\s*([^\s\[\]:]+):?\s*([^\]\n]+)?\]\]/img;
|
|
44
50
|
const replacerArgsRegex = /\s*,+\s*/;
|
|
45
51
|
const replacers = [
|
|
@@ -54,33 +60,33 @@ module.exports = function (options = {}) {
|
|
|
54
60
|
|
|
55
61
|
prepareTref(path.join(config.specs[0].spec_directory, config.specs[0].spec_terms_directory));
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
// Synchronously process markdown files
|
|
64
|
+
fixMarkdownFiles(path.join(config.specs[0].spec_directory, config.specs[0].spec_terms_directory));
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
function createScriptElementWithXTrefDataForEmbeddingInHtml() {
|
|
67
|
+
// Test if xtrefs-data.js exists, else make it an empty string
|
|
68
|
+
const inputPath = path.join('output', 'xtrefs-data.js');
|
|
63
69
|
|
|
64
|
-
let xtrefsData =
|
|
70
|
+
let xtrefsData = '';
|
|
65
71
|
if (fs.existsSync(inputPath)) {
|
|
66
72
|
xtrefsData = '<script>' + fs.readFileSync(inputPath, 'utf8') + '</script>';
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
return xtrefsData;
|
|
76
|
+
}
|
|
71
77
|
|
|
72
|
-
|
|
78
|
+
const xtrefsData = createScriptElementWithXTrefDataForEmbeddingInHtml();
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
function applyReplacers(doc) {
|
|
81
|
+
return doc.replace(replacerRegex, function (match, type, args) {
|
|
82
|
+
let replacer = replacers.find(r => type.trim().match(r.test));
|
|
83
|
+
return replacer ? replacer.transform(...args.trim().split(replacerArgsRegex)) : match;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
function normalizePath(path) {
|
|
88
|
+
return path.trim().replace(/\/$/g, '') + '/';
|
|
89
|
+
}
|
|
84
90
|
|
|
85
91
|
function renderRefGroup(type) {
|
|
86
92
|
let group = specGroups[type];
|
|
@@ -94,356 +100,370 @@ module.exports = function (options = {}) {
|
|
|
94
100
|
${ref.authors.join('; ')}; ${ref.rawDate}. <span class="reference-status">Status: ${ref.status}</span>.
|
|
95
101
|
</dd>
|
|
96
102
|
`;
|
|
97
|
-
}, '<dl class="reference-list">')
|
|
103
|
+
}, '<dl class="reference-list">');
|
|
98
104
|
return `\n${html}\n</dl>\n`;
|
|
99
105
|
}
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
function findKatexDist() {
|
|
108
|
+
const relpath = "node_modules/katex/dist";
|
|
109
|
+
const paths = [
|
|
110
|
+
path.join(process.cwd(), relpath),
|
|
111
|
+
path.join(__dirname, relpath),
|
|
112
|
+
];
|
|
113
|
+
for (const abspath of paths) {
|
|
114
|
+
if (fs.existsSync(abspath)) {
|
|
115
|
+
return abspath
|
|
116
|
+
}
|
|
110
117
|
}
|
|
118
|
+
throw Error("katex distribution could not be located");
|
|
111
119
|
}
|
|
112
|
-
throw Error("katex distribution could not be located");
|
|
113
|
-
}
|
|
114
120
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
// Custom plugin to add class to <dl> and the last <dd> in each series after a <dt>
|
|
122
|
+
function addClassToDefinitionList(md) {
|
|
123
|
+
const originalRender = md.renderer.rules.dl_open || function (tokens, idx, options, env, self) {
|
|
124
|
+
return self.renderToken(tokens, idx, options);
|
|
125
|
+
};
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
// Variable to keep track of whether the class has been added to the first <dl> after the target HTML
|
|
128
|
+
let classAdded = false;
|
|
123
129
|
|
|
124
|
-
|
|
130
|
+
md.renderer.rules.dl_open = function (tokens, idx, options, env, self) {
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
const targetHtml = 'terminology-section-start-h7vc6omi2hr2880';
|
|
133
|
+
let targetIndex = -1;
|
|
128
134
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
// Find the index of the target HTML
|
|
136
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
137
|
+
if (tokens[i].content && tokens[i].content.includes(targetHtml)) {
|
|
138
|
+
targetIndex = i;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
134
141
|
}
|
|
135
|
-
}
|
|
136
142
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
// Add class to the first <dl> only if it comes after the target HTML
|
|
144
|
+
if (targetIndex !== -1 && idx > targetIndex && !classAdded) {
|
|
145
|
+
tokens[idx].attrPush(['class', 'terms-and-definitions-list']);
|
|
146
|
+
classAdded = true;
|
|
147
|
+
}
|
|
142
148
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
let lastDdIndex = -1;
|
|
150
|
+
|
|
151
|
+
for (let i = idx + 1; i < tokens.length; i++) {
|
|
152
|
+
if (tokens[i].type === 'dl_close') {
|
|
153
|
+
// Add class to the last <dd> before closing <dl>
|
|
154
|
+
if (lastDdIndex !== -1) {
|
|
155
|
+
const ddToken = tokens[lastDdIndex];
|
|
156
|
+
const classIndex = ddToken.attrIndex('class');
|
|
157
|
+
if (classIndex < 0) {
|
|
158
|
+
ddToken.attrPush(['class', 'last-dd']);
|
|
159
|
+
} else {
|
|
160
|
+
ddToken.attrs[classIndex][1] += ' last-dd';
|
|
161
|
+
}
|
|
155
162
|
}
|
|
163
|
+
break;
|
|
156
164
|
}
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
165
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
if (tokens[i].type === 'dt_open') {
|
|
167
|
+
// Add class to the last <dd> before a new <dt>
|
|
168
|
+
if (lastDdIndex !== -1) {
|
|
169
|
+
const ddToken = tokens[lastDdIndex];
|
|
170
|
+
const classIndex = ddToken.attrIndex('class');
|
|
171
|
+
if (classIndex < 0) {
|
|
172
|
+
ddToken.attrPush(['class', 'last-dd']);
|
|
173
|
+
} else {
|
|
174
|
+
ddToken.attrs[classIndex][1] += ' last-dd';
|
|
175
|
+
}
|
|
176
|
+
lastDdIndex = -1; // Reset for the next series
|
|
169
177
|
}
|
|
170
|
-
lastDdIndex = -1; // Reset for the next series
|
|
171
178
|
}
|
|
172
|
-
}
|
|
173
179
|
|
|
174
|
-
|
|
175
|
-
|
|
180
|
+
if (tokens[i].type === 'dd_open') {
|
|
181
|
+
lastDdIndex = i;
|
|
182
|
+
}
|
|
176
183
|
}
|
|
177
|
-
}
|
|
178
184
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
185
|
+
return originalRender(tokens, idx, options, env, self);
|
|
186
|
+
};
|
|
187
|
+
}
|
|
182
188
|
|
|
183
|
-
|
|
189
|
+
try {
|
|
184
190
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
191
|
+
var toc;
|
|
192
|
+
var specGroups = {};
|
|
193
|
+
const noticeTypes = {
|
|
194
|
+
note: 1,
|
|
195
|
+
issue: 1,
|
|
196
|
+
example: 1,
|
|
197
|
+
warning: 1,
|
|
198
|
+
todo: 1
|
|
199
|
+
};
|
|
200
|
+
const spaceRegex = /\s+/g;
|
|
201
|
+
const specNameRegex = /^spec$|^spec[-]*\w+$/i;
|
|
202
|
+
const terminologyRegex = /^def$|^ref$|^xref|^tref$/i;
|
|
203
|
+
const specCorpus = fs.readJsonSync(modulePath + '/assets/compiled/refs.json');
|
|
204
|
+
const containers = require('markdown-it-container');
|
|
205
|
+
|
|
206
|
+
/*
|
|
207
|
+
`const md` is assigned an instance of the markdown-it parser configured with various plugins and extensions. This instance (md) is intended to be used later to parse and render Markdown strings.
|
|
208
|
+
|
|
209
|
+
The md function (which is an instance of the markdown-it parser) takes a Markdown string as its primary argument. It is called elsewhere as follows: `md.render(doc)`
|
|
210
|
+
*/
|
|
211
|
+
const md = require('markdown-it')({
|
|
212
|
+
html: true,
|
|
213
|
+
linkify: true,
|
|
214
|
+
typographer: true
|
|
215
|
+
})
|
|
216
|
+
.use(require('./src/markdown-it-extensions.js'), [
|
|
217
|
+
{
|
|
218
|
+
filter: type => type.match(terminologyRegex),
|
|
219
|
+
parse(token, type, primary) {
|
|
220
|
+
if (!primary) return;
|
|
221
|
+
if (type === 'def') {
|
|
222
|
+
definitions.push(token.info.args);
|
|
223
|
+
return token.info.args.reduce((acc, syn) => {
|
|
224
|
+
return `<span id="term:${syn.replace(spaceRegex, '-').toLowerCase()}">${acc}</span>`;
|
|
225
|
+
}, primary);
|
|
226
|
+
}
|
|
227
|
+
else if (type === 'xref') {
|
|
228
|
+
const url = findExternalSpecByKey(config, token.info.args[0]);
|
|
229
|
+
const term = token.info.args[1].replace(spaceRegex, '-').toLowerCase();
|
|
230
|
+
return `<a class="x-term-reference term-reference" data-local-href="#term:${token.info.args[0]}:${term}"
|
|
219
231
|
href="${url}#term:${term}">${token.info.args[1]}</a>`;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
filter: type => type.match(specNameRegex),
|
|
232
|
-
parse(token, type, name) {
|
|
233
|
-
if (name) {
|
|
234
|
-
let _name = name.replace(spaceRegex, '-').toUpperCase();
|
|
235
|
-
let spec = specCorpus[_name] ||
|
|
236
|
-
specCorpus[_name.toLowerCase()] ||
|
|
237
|
-
specCorpus[name.toLowerCase()] ||
|
|
238
|
-
specCorpus[name];
|
|
239
|
-
if (spec) {
|
|
240
|
-
spec._name = _name;
|
|
241
|
-
let group = specGroups[type] = specGroups[type] || {};
|
|
242
|
-
token.info.spec = group[_name] = spec;
|
|
232
|
+
}
|
|
233
|
+
else if (type === 'tref') {
|
|
234
|
+
return `<span class="transcluded-xref-term" id="term:${token.info.args[1]}">${token.info.args[1]}</span>`;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
references.push(primary);
|
|
238
|
+
return `<a class="term-reference" href="#term:${primary.replace(spaceRegex, '-').toLowerCase()}">${primary}</a>`;
|
|
243
239
|
}
|
|
244
240
|
}
|
|
245
241
|
},
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (
|
|
242
|
+
{
|
|
243
|
+
filter: type => type.match(specNameRegex),
|
|
244
|
+
parse(token, type, name) {
|
|
245
|
+
if (name) {
|
|
246
|
+
let _name = name.replace(spaceRegex, '-').toUpperCase();
|
|
247
|
+
let spec = specCorpus[_name] ||
|
|
248
|
+
specCorpus[_name.toLowerCase()] ||
|
|
249
|
+
specCorpus[name.toLowerCase()] ||
|
|
250
|
+
specCorpus[name];
|
|
251
|
+
if (spec) {
|
|
252
|
+
spec._name = _name;
|
|
253
|
+
let group = specGroups[type] = specGroups[type] || {};
|
|
254
|
+
token.info.spec = group[_name] = spec;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
render(token, type, name) {
|
|
259
|
+
if (name) {
|
|
260
|
+
let spec = token.info.spec;
|
|
261
|
+
if (spec) return `[<a class="spec-reference" href="#ref:${spec._name}">${spec._name}</a>]`;
|
|
262
|
+
}
|
|
263
|
+
else return renderRefGroup(type);
|
|
250
264
|
}
|
|
251
|
-
else return renderRefGroup(type);
|
|
252
265
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
266
|
+
])
|
|
267
|
+
.use(require('markdown-it-attrs'))
|
|
268
|
+
.use(require('markdown-it-chart').default)
|
|
269
|
+
.use(require('markdown-it-deflist'))
|
|
270
|
+
.use(require('markdown-it-references'))
|
|
271
|
+
.use(require('markdown-it-icons').default, 'font-awesome')
|
|
272
|
+
.use(require('markdown-it-ins'))
|
|
273
|
+
.use(require('markdown-it-mark'))
|
|
274
|
+
.use(require('markdown-it-textual-uml'))
|
|
275
|
+
.use(require('markdown-it-sub'))
|
|
276
|
+
.use(require('markdown-it-sup'))
|
|
277
|
+
.use(require('markdown-it-task-lists'))
|
|
278
|
+
.use(require('markdown-it-multimd-table'), {
|
|
279
|
+
multiline: true,
|
|
280
|
+
rowspan: true,
|
|
281
|
+
headerless: true
|
|
282
|
+
})
|
|
283
|
+
.use(containers, 'notice', {
|
|
284
|
+
validate: function (params) {
|
|
285
|
+
let matches = params.match(/(\w+)\s?(.*)?/);
|
|
286
|
+
return matches && noticeTypes[matches[1]];
|
|
287
|
+
},
|
|
288
|
+
render: function (tokens, idx) {
|
|
289
|
+
let matches = tokens[idx].info.match(/(\w+)\s?(.*)?/);
|
|
290
|
+
if (matches && tokens[idx].nesting === 1) {
|
|
291
|
+
let id;
|
|
292
|
+
let type = matches[1];
|
|
293
|
+
if (matches[2]) {
|
|
294
|
+
id = matches[2].trim().replace(/\s+/g, '-').toLowerCase();
|
|
295
|
+
if (noticeTitles[id]) id += '-' + noticeTitles[id]++;
|
|
296
|
+
else noticeTitles[id] = 1;
|
|
297
|
+
}
|
|
298
|
+
else id = type + '-' + noticeTypes[type]++;
|
|
299
|
+
return `<div id="${id}" class="notice ${type}"><a class="notice-link" href="#${id}">${type.toUpperCase()}</a>`;
|
|
285
300
|
}
|
|
286
|
-
else
|
|
287
|
-
|
|
301
|
+
else return '</div>\n';
|
|
302
|
+
}
|
|
303
|
+
})
|
|
304
|
+
.use(require('markdown-it-prism'))
|
|
305
|
+
.use(require('markdown-it-toc-and-anchor').default, {
|
|
306
|
+
tocClassName: 'toc',
|
|
307
|
+
tocFirstLevel: 2,
|
|
308
|
+
tocLastLevel: 4,
|
|
309
|
+
tocCallback: (_md, _tokens, html) => toc = html,
|
|
310
|
+
anchorLinkSymbol: '#', // was: §
|
|
311
|
+
anchorClassName: 'toc-anchor'
|
|
312
|
+
})
|
|
313
|
+
.use(require('@traptitech/markdown-it-katex'))
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
md.use(addClassToDefinitionList);
|
|
318
|
+
|
|
319
|
+
async function render(spec, assets) {
|
|
320
|
+
try {
|
|
321
|
+
noticeTitles = {};
|
|
322
|
+
specGroups = {};
|
|
323
|
+
console.log('\n SPEC-UP-T: Rendering: ' + spec.title + "\n");
|
|
324
|
+
|
|
325
|
+
function interpolate(template, variables) {
|
|
326
|
+
return template.replace(/\${(.*?)}/g, (match, p1) => variables[p1.trim()]);
|
|
288
327
|
}
|
|
289
|
-
else return '</div>\n';
|
|
290
|
-
}
|
|
291
|
-
})
|
|
292
|
-
.use(require('markdown-it-prism'))
|
|
293
|
-
.use(require('markdown-it-toc-and-anchor').default, {
|
|
294
|
-
tocClassName: 'toc',
|
|
295
|
-
tocFirstLevel: 2,
|
|
296
|
-
tocLastLevel: 4,
|
|
297
|
-
tocCallback: (_md, _tokens, html) => toc = html,
|
|
298
|
-
anchorLinkSymbol: '#', // was: §
|
|
299
|
-
anchorClassName: 'toc-anchor'
|
|
300
|
-
})
|
|
301
|
-
.use(require('@traptitech/markdown-it-katex'))
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
md.use(addClassToDefinitionList);
|
|
306
|
-
|
|
307
|
-
async function render(spec, assets) {
|
|
308
|
-
try {
|
|
309
|
-
noticeTitles = {};
|
|
310
|
-
specGroups = {};
|
|
311
|
-
console.log('\n SPEC-UP-T: Rendering: ' + spec.title + "\n");
|
|
312
|
-
|
|
313
|
-
function interpolate(template, variables) {
|
|
314
|
-
return template.replace(/\${(.*?)}/g, (match, p1) => variables[p1.trim()]);
|
|
315
|
-
}
|
|
316
328
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
329
|
+
return new Promise(async (resolve, reject) => {
|
|
330
|
+
Promise.all((spec.markdown_paths || ['spec.md']).map(_path => {
|
|
331
|
+
return fs.readFile(spec.spec_directory + _path, 'utf8').catch(e => reject(e))
|
|
332
|
+
})).then(async docs => {
|
|
333
|
+
const features = (({ source, logo }) => ({ source, logo }))(spec);
|
|
334
|
+
if (spec.external_specs && !externalReferences) {
|
|
335
|
+
externalReferences = await fetchExternalSpecs(spec);
|
|
336
|
+
}
|
|
325
337
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
338
|
+
// Find the index of the terms-and-definitions-intro.md file
|
|
339
|
+
const termsIndex = (spec.markdown_paths || ['spec.md']).indexOf('terms-and-definitions-intro.md');
|
|
340
|
+
if (termsIndex !== -1) {
|
|
341
|
+
// Append the HTML string to the content of terms-and-definitions-intro.md. This string is used to create a div that is used to insert an alphabet index, and a div that is used as the starting point of the terminology index. The newlines are essential for the correct rendering of the markdown.
|
|
342
|
+
docs[termsIndex] += '\n\n<div id="alphabet-index-h7vc6omi2hr2880"></div>\n\n<div id="terminology-section-start-h7vc6omi2hr2880"></div>\n\n<hr>\n\n';
|
|
343
|
+
}
|
|
332
344
|
|
|
333
|
-
|
|
345
|
+
let doc = docs.join("\n");
|
|
346
|
+
|
|
347
|
+
// `doc` is markdown
|
|
334
348
|
doc = applyReplacers(doc);
|
|
349
|
+
|
|
335
350
|
md[spec.katex ? "enable" : "disable"](katexRules);
|
|
351
|
+
|
|
352
|
+
// `render` is the rendered HTML
|
|
336
353
|
const render = md.render(doc);
|
|
337
354
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
fs.writeFile(path.join(spec.destination, 'index.html'),
|
|
357
|
-
templateInterpolated, 'utf8'
|
|
358
|
-
|
|
359
|
-
, function (err, data) {
|
|
360
|
-
if (err) {
|
|
361
|
-
reject(err);
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
resolve();
|
|
365
|
-
}
|
|
355
|
+
const templateInterpolated = interpolate(template, {
|
|
356
|
+
title: spec.title,
|
|
357
|
+
description: spec.description,
|
|
358
|
+
author: spec.author,
|
|
359
|
+
toc: toc,
|
|
360
|
+
render: render,
|
|
361
|
+
assetsHead: assets.head,
|
|
362
|
+
assetsBody: assets.body,
|
|
363
|
+
assetsSvg: assets.svg,
|
|
364
|
+
features: Object.keys(features).join(' '),
|
|
365
|
+
externalReferences: JSON.stringify(externalReferences),
|
|
366
|
+
xtrefsData: xtrefsData,
|
|
367
|
+
specLogo: spec.logo,
|
|
368
|
+
specFavicon: spec.favicon,
|
|
369
|
+
specLogoLink: spec.logo_link,
|
|
370
|
+
spec: JSON.stringify(spec)
|
|
366
371
|
});
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
372
|
+
|
|
373
|
+
fs.writeFile(path.join(spec.destination, 'index.html'),
|
|
374
|
+
templateInterpolated, 'utf8'
|
|
375
|
+
|
|
376
|
+
, function (err, data) {
|
|
377
|
+
if (err) {
|
|
378
|
+
reject(err);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
resolve();
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
validateReferences(references, definitions, render);
|
|
385
|
+
references = [];
|
|
386
|
+
definitions = [];
|
|
387
|
+
});
|
|
370
388
|
});
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
389
|
+
}
|
|
390
|
+
catch (e) {
|
|
391
|
+
console.error("\n SPEC-UP-T: " + e + "\n");
|
|
392
|
+
}
|
|
375
393
|
}
|
|
376
|
-
}
|
|
377
394
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
395
|
+
config.specs.forEach(spec => {
|
|
396
|
+
spec.spec_directory = normalizePath(spec.spec_directory);
|
|
397
|
+
spec.destination = normalizePath(spec.output_path || spec.spec_directory);
|
|
381
398
|
|
|
382
|
-
|
|
399
|
+
fs.ensureDirSync(spec.destination);
|
|
383
400
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
401
|
+
let assetTags = {
|
|
402
|
+
svg: fs.readFileSync(modulePath + '/assets/icons.svg', 'utf8') || ''
|
|
403
|
+
};
|
|
387
404
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
405
|
+
let customAssets = (spec.assets || []).reduce((assets, asset) => {
|
|
406
|
+
let ext = asset.path.split('.').pop();
|
|
407
|
+
if (ext === 'css') {
|
|
408
|
+
assets.css += `<link href="${asset.path}" rel="stylesheet"/>`;
|
|
409
|
+
}
|
|
410
|
+
if (ext === 'js') {
|
|
411
|
+
assets.js[asset.inject || 'body'] += `<script src="${asset.path}" ${asset.module ? 'type="module"' : ''} ></script>`;
|
|
412
|
+
}
|
|
413
|
+
return assets;
|
|
414
|
+
}, {
|
|
415
|
+
css: '',
|
|
416
|
+
js: { head: '', body: '' }
|
|
417
|
+
});
|
|
401
418
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
419
|
+
if (options.dev) {
|
|
420
|
+
assetTags.head = assets.head.css.map(_path => `<link href="${_path}" rel="stylesheet"/>`).join('') +
|
|
421
|
+
customAssets.css +
|
|
422
|
+
assets.head.js.map(_path => `<script src="${_path}"></script>`).join('') +
|
|
423
|
+
customAssets.js.head;
|
|
424
|
+
assetTags.body = assets.body.js.map(_path => `<script src="${_path}" data-manual></script>`).join('') +
|
|
425
|
+
customAssets.js.body;
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
assetTags.head = `
|
|
412
429
|
<style>${fs.readFileSync(modulePath + '/assets/compiled/head.css', 'utf8')}</style>
|
|
413
430
|
${customAssets.css}
|
|
414
431
|
<script>${fs.readFileSync(modulePath + '/assets/compiled/head.js', 'utf8')}</script>
|
|
415
432
|
${customAssets.js.head}
|
|
416
433
|
`;
|
|
417
|
-
|
|
434
|
+
assetTags.body = `<script>${fs.readFileSync(modulePath + '/assets/compiled/body.js', 'utf8')}</script>
|
|
418
435
|
${customAssets.js.body}`;
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if (spec.katex) {
|
|
422
|
-
const katexDist = findKatexDist();
|
|
423
|
-
assetTags.body += `<script>/* katex */${fs.readFileSync(path.join(katexDist, 'katex.min.js'),
|
|
424
|
-
'utf8')}</script>`;
|
|
425
|
-
assetTags.body += `<style>/* katex */${fs.readFileSync(path.join(katexDist, 'katex.min.css'),
|
|
426
|
-
'utf8')}</style>`;
|
|
436
|
+
}
|
|
427
437
|
|
|
428
|
-
|
|
429
|
-
|
|
438
|
+
if (spec.katex) {
|
|
439
|
+
const katexDist = findKatexDist();
|
|
440
|
+
assetTags.body += `<script>/* katex */${fs.readFileSync(path.join(katexDist, 'katex.min.js'),
|
|
441
|
+
'utf8')}</script>`;
|
|
442
|
+
assetTags.body += `<style>/* katex */${fs.readFileSync(path.join(katexDist, 'katex.min.css'),
|
|
443
|
+
'utf8')}</style>`;
|
|
430
444
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
[spec.spec_directory + '**/*', '!' + path.join(spec.destination, 'index.html')],
|
|
434
|
-
render.bind(null, spec, assetTags)
|
|
435
|
-
)
|
|
436
|
-
}
|
|
445
|
+
fs.copySync(path.join(katexDist, 'fonts'), path.join(spec.destination, 'fonts'));
|
|
446
|
+
}
|
|
437
447
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
448
|
+
if (!options.nowatch) {
|
|
449
|
+
gulp.watch(
|
|
450
|
+
[spec.spec_directory + '**/*', '!' + path.join(spec.destination, 'index.html')],
|
|
451
|
+
render.bind(null, spec, assetTags)
|
|
452
|
+
)
|
|
453
|
+
}
|
|
441
454
|
|
|
442
|
-
|
|
455
|
+
render(spec, assetTags).then(() => {
|
|
456
|
+
if (options.nowatch) process.exit(0)
|
|
457
|
+
}).catch(() => process.exit(1));
|
|
443
458
|
|
|
459
|
+
});
|
|
460
|
+
console.log('Module function executed successfully.');
|
|
461
|
+
} catch (error) {
|
|
462
|
+
console.error(`Error during initialization or module execution: ${error.message}`);
|
|
463
|
+
throw error; // Re-throw to let the caller handle the error
|
|
464
|
+
}
|
|
465
|
+
} catch (error) {
|
|
466
|
+
console.error(`Error during initialization: ${error.message}`);
|
|
467
|
+
throw error; // Re-throw to let the caller handle the error
|
|
444
468
|
}
|
|
445
|
-
|
|
446
|
-
console.error("\n SPEC-UP-T: " + e + "\n");
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
}
|
|
469
|
+
};
|