Skip to content

Commit 3a70513

Browse files
committed
md2html: improved code blocks
1 parent 08f92ad commit 3a70513

1 file changed

Lines changed: 73 additions & 103 deletions

File tree

scripts/md2html/md2html.js

Lines changed: 73 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ complete control over formatting and syntax highlighting */
55
'use strict';
66

77
/**
8-
@author Mike Ralphson <mike.ralphson@gmail.com>
9-
**/
8+
* @author Mike Ralphson <mike.ralphson@gmail.com>
9+
**/
1010

1111
const fs = require('fs');
1212
const path = require('path');
@@ -34,9 +34,9 @@ const md = require('markdown-it')({
3434
linkify: true,
3535
typographer: true,
3636
highlight: function (str, lang) {
37-
if (lang && hljs.getLanguage(lang)) { // && !argv.respec) {
37+
if (lang && hljs.getLanguage(lang)) {
3838
try {
39-
return '<pre class="nohighlight"><code>' +
39+
return '<pre class="nohighlight" tabindex="0"><code>' +
4040
hljs.highlight(str, { language: lang }).value +
4141
'</code></pre>';
4242
} catch (__) { }
@@ -86,56 +86,9 @@ function preface(title,options) {
8686
],
8787
},
8888
],
89-
localBiblio: {
90-
"OpenAPI-Learn": {
91-
title: "OpenAPI - Getting started, and the specification explained",
92-
href: "https://learn.openapis.org/",
93-
publisher: "OpenAPI Initiative"
94-
},
95-
"OpenAPI-Registry": {
96-
title: "OpenAPI Initiative Registry",
97-
href: "https://spec.openapis.org/registry/index.html",
98-
publisher: "OpenAPI Initiative"
99-
},
100-
//TODO: remove localBiblio once Specref PRs https://github.com/tobie/specref/pulls/ralfhandl are merged
101-
"JSON-Schema-Validation-04": {
102-
authors: [ "Kris Zyp", "Francis Galiegue", "Gary Court" ],
103-
href: "https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00",
104-
publisher: "Internet Engineering Task Force (IETF)",
105-
status: "Internet-Draft",
106-
title: "JSON Schema: interactive and non interactive validation. Draft 4",
107-
date: "1 February 2013"
108-
},
109-
"JSON-Schema-05": {
110-
authors: [ "Austin Wright" ],
111-
href: "https://datatracker.ietf.org/doc/html/draft-wright-json-schema-00",
112-
publisher: "Internet Engineering Task Force (IETF)",
113-
status: "Internet-Draft",
114-
title: "JSON Schema: A Media Type for Describing JSON Documents. Draft 5",
115-
date: "13 October 2016"
116-
},
117-
"JSON-Schema-Validation-05": {
118-
authors: [ "Austin Wright", "G. Luff" ],
119-
href: "https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00",
120-
publisher: "Internet Engineering Task Force (IETF)",
121-
status: "Internet-Draft",
122-
title: "JSON Schema Validation: A Vocabulary for Structural Validation of JSON. Draft 5",
123-
date: "13 October 2016"
124-
},
125-
"JSON-Schema-Validation-2020-12": {
126-
authors: [ "Austin Wright", "Henry Andrews", "Ben Hutton" ],
127-
href: "https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00",
128-
publisher: "Internet Engineering Task Force (IETF)",
129-
status: "Internet-Draft",
130-
title: "JSON Schema Validation: A Vocabulary for Structural Validation of JSON. Draft 2020-12",
131-
date: "8 December 2020"
132-
},
133-
"SPDX": {
134-
href: "https://spdx.org/licenses/",
135-
title: "SPDX License List",
136-
publisher: "Linux Foundation"
137-
}
138-
}
89+
// localBiblio: {
90+
// // add local bibliography entries here, add them to https://www.specref.org/, and remove them here once published
91+
// }
13992
};
14093

14194
let preface = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>${md.utils.escapeHtml(title)}</title>`;
@@ -154,9 +107,10 @@ function preface(title,options) {
154107
preface += '</head><body>';
155108
preface += '<style>';
156109
preface += '#respec-ui { visibility: hidden; }';
157-
preface += 'h1,h2,h3 { color: #629b34; }';
158-
preface += '.dt-published { color: #629b34; } .dt-published::before { content: "Published "; }';
159-
preface += 'a[href] { color: #45512c; }'; // third OAI colour is #8ad000
110+
preface += '#title { color: #578000; } #subtitle { color: #578000; }';
111+
preface += '.dt-published { color: #578000; } .dt-published::before { content: "Published "; }';
112+
preface += 'h1,h2,h3,h4,h5,h6 { color: #578000; font-weight: normal; font-style: normal; }';
113+
preface += 'a[href] { color: #45512c; }';
160114
preface += 'body:not(.toc-inline) #toc h2 { color: #45512c; }';
161115
preface += 'table { display: block; width: 100%; overflow: auto; }';
162116
preface += 'table th { font-weight: 600; }';
@@ -247,68 +201,30 @@ let indents = [0];
247201
for (let l in lines) {
248202
let line = lines[l];
249203

204+
// remove TOC from older spec versions, respec will generate a new one
250205
if (line.startsWith('## Table of Contents')) inTOC = true;
251206
if (line.startsWith('<!-- /TOC')) inTOC = false;
252207
if (inTOC) line = '';
253208

209+
// special formatting for Definitions section
254210
if (line.startsWith('## Definitions')) {
255211
inDefs = true;
256212
bsFix = false;
257213
}
258214
else if (line.startsWith('## ')) inDefs = false;
259215

216+
// recognize code blocks
260217
if (line.startsWith('```')) {
261218
inCodeBlock = !inCodeBlock;
262-
line += '\n'; // fixes formatting of first line of syntax-highlighted blocks
263-
}
264-
265-
if (!inCodeBlock && line.startsWith('#')) {
266-
let indent = 0;
267-
while (line[indent] === '#') indent++;
268-
let originalIndent = indent;
269-
270-
let prevIndent = indents[indents.length-1]; // peek
271-
let delta = indent-prevIndent;
272-
273-
if (!argv.respec) {
274-
if (delta===0) indent = lastIndent
275-
else if (delta<0) indent = lastIndent-1
276-
else if (delta>0) indent = lastIndent+1;
277-
}
278-
279-
if (indent < 0) {
280-
indent = 1;
281-
}
282-
if (argv.respec && (indent > 1)) {
283-
indent--;
284-
}
285-
let newIndent = indent;
286-
if (!argv.respec && (indent <= 2) && bsFix) {
287-
newIndent++;
288-
}
289-
290-
let title = line.split('# ')[1];
291-
if (inDefs) title = '<dfn>'+title+'</dfn>';
292-
line = ('#'.repeat(newIndent)+' '+title);
293-
294-
if (delta>0) indents.push(originalIndent);
295-
if (delta<0) {
296-
let d = Math.abs(delta);
297-
while (d>0) {
298-
indents.pop();
299-
d--;
300-
}
301-
}
302-
lastIndent = indent;
303219
}
304220

305221
if (line.indexOf('<a name="')>=0) {
306222
if (line.indexOf('<a name="parameterAllowEmptyValue"/>')>=0)
307223
// fix syntax error in 2.0.md
308224
line = line.replace('<a name="parameterAllowEmptyValue"/>','<span id="parameterAllowEmptyValue"></span>');
309225
else {
310-
line = line.replace('<a name=','<span id=');
311-
line = line.replace('</a>','</span>');
226+
// replace deprecated <a name="..."></a> with <span id="..."></span>
227+
line = line.replace(/<a name="([^"]+)"><\/a>/g,'<span id="$1"></span>');
312228
}
313229
}
314230

@@ -352,6 +268,7 @@ for (let l in lines) {
352268
line = line.replace('consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4)','consult [[HTML401]] [Section 17.13.4](http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4)');
353269
line = line.replace('[IANA Status Code Registry](https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml)','[[IANA-HTTP-STATUS-CODES|IANA Status Code Registry]]');
354270
line = line.replace('[IANA Authentication Scheme registry](https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml)','[[IANA-HTTP-AUTHSCHEMES]]');
271+
line = line.replace('[JSON Reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)','[[JSON-Reference|JSON Reference]]');
355272
line = line.replace('[JSON Schema Specification Draft 4](https://json-schema.org/)','[[JSON-Schema-04|JSON Schema Specification Draft 4]]');
356273
line = line.replace('[JSON Schema Core](https://tools.ietf.org/html/draft-zyp-json-schema-04)','[[JSON-Schema-04|JSON Schema Core]]');
357274
line = line.replace('[JSON Schema Validation](https://tools.ietf.org/html/draft-fge-json-schema-validation-00)','[[JSON-Schema-Validation-04|JSON Schema Validation]]');
@@ -361,13 +278,15 @@ for (let l in lines) {
361278
line = line.replace('[JSON Schema Specification Draft 2020-12](https://tools.ietf.org/html/draft-bhutton-json-schema-00)','[[JSON-Schema-2020-12|JSON Schema Specification Draft 2020-12]]');
362279
line = line.replace('[JSON Schema Core](https://tools.ietf.org/html/draft-bhutton-json-schema-00)','[[JSON-Schema-2020-12|JSON Schema Core]]');
363280
line = line.replace('[JSON Schema Validation](https://tools.ietf.org/html/draft-bhutton-json-schema-validation-00)','[[JSON-Schema-Validation-2020-12|JSON Schema Validation]]');
364-
line = line.replace('[SPDX](https://spdx.org/licenses/)','[[SPDX]]');
281+
line = line.replace('[SPDX](https://spdx.org/licenses/) license','[[SPDX-Licenses]]');
365282
line = line.replace('[XML namespaces](https://www.w3.org/TR/xml-names11/)','[[xml-names11|XML namespaces]]');
366283
line = line.replace('JSON standards. YAML,','[[RFC7159|JSON]] standards. [[YAML|YAML]],'); // 2.0.md only
367284
line = line.replace('JSON or YAML format.','[[RFC7159|JSON]] or [[YAML|YAML]] format.');
368285
line = line.replace(/YAML version \[1\.2\]\(https:\/\/(www\.)?yaml\.org\/spec\/1\.2\/spec\.html\)/,'[[YAML|YAML version 1.2]]');
369286
}
370287

288+
// fix relative links (to examples)
289+
//TODO: adjust when moving examples to a different repo
371290
if (!inCodeBlock && line.indexOf('](../') >= 0) {
372291
const regExp = /\((\.\.[^)]+)\)/g;
373292
line = line.replace(regExp,function(match,group1){
@@ -376,6 +295,50 @@ for (let l in lines) {
376295
});
377296
}
378297

298+
// fix indentation of headings
299+
// - make sure that each heading is at most one level deeper than the previous heading
300+
// - reduce heading level by one if we're in respec mode except for h1
301+
if (!inCodeBlock && line.startsWith('#')) {
302+
let indent = 0;
303+
while (line[indent] === '#') indent++;
304+
let originalIndent = indent;
305+
306+
let prevIndent = indents[indents.length-1]; // peek
307+
let delta = indent-prevIndent;
308+
309+
if (!argv.respec) {
310+
if (delta===0) indent = lastIndent
311+
else if (delta<0) indent = lastIndent-1
312+
else if (delta>0) indent = lastIndent+1;
313+
}
314+
315+
if (indent < 0) {
316+
indent = 1;
317+
}
318+
if (argv.respec && (indent > 1)) {
319+
indent--;
320+
}
321+
let newIndent = indent;
322+
if (!argv.respec && (indent <= 2) && bsFix) {
323+
newIndent++;
324+
}
325+
326+
let title = line.split('# ')[1];
327+
if (inDefs) title = '<dfn>'+title+'</dfn>';
328+
line = ('#'.repeat(newIndent)+' '+title);
329+
330+
if (delta>0) indents.push(originalIndent);
331+
if (delta<0) {
332+
let d = Math.abs(delta);
333+
while (d>0) {
334+
indents.pop();
335+
d--;
336+
}
337+
}
338+
lastIndent = indent;
339+
}
340+
341+
// wrap section text in <section>...</section> tags for respec
379342
if (!inCodeBlock && argv.respec && line.startsWith('#')) {
380343
let heading = 0;
381344
while (line[heading] === '#') heading++;
@@ -384,16 +347,23 @@ for (let l in lines) {
384347
if (delta>0) delta = 1;
385348
let prefix = '';
386349
let newSection = '<section>';
387-
if (line.includes('## Version ')) {
350+
const m = line.match(/# Version ([0-9.]+)$/);
351+
if (m) {
388352
// our conformance section is headlined with 'Version x.y.z'
353+
// and respec needs a conformance section in a "formal" specification
389354
newSection = '<section class="override" id="conformance">';
355+
// adjust the heading to be at level 2 because respec insists on h2 here
356+
// Note: older specs had this at h4, newer specs at h2, and all heading levels have been reduced by 1 in the preceding block
357+
line = '#' + m[0];
358+
delta = 1;
359+
heading = 2;
390360
}
391361
if (line.includes('Appendix')) {
392362
newSection = '<section class="appendix">';
393363
}
394364

395365
// heading level delta is either 0 or is +1/-1, or we're in respec mode
396-
/* respec insists on <section>...</section> breaks around headings */
366+
// respec insists on <section>...</section> breaks around headings
397367

398368
if (delta === 0) {
399369
prefix = '</section>'+newSection;

0 commit comments

Comments
 (0)