@@ -4,7 +4,7 @@ const jsdom = require("jsdom");
44const { JSDOM } = jsdom ;
55const path = require ( "path" ) ;
66const markedAlert = require ( "marked-alert" ) ;
7-
7+ const matter = require ( "gray-matter" ) ;
88// Setup some options for our markdown renderer
99marked . setOptions ( {
1010 renderer : new marked . Renderer ( ) ,
@@ -34,9 +34,13 @@ marked.use(markedAlert());
3434async function renderit ( infile ) {
3535 const gtag = ( await fs . readFile ( "gtag.html" , "utf-8" ) ) . trim ( ) ;
3636 console . log ( `Reading ${ infile } ` ) ;
37- basename = path . basename ( infile , ".md" ) ;
37+ const basename = path . basename ( infile , ".md" ) ;
3838 const outfile = path . join ( path . dirname ( infile ) , `${ basename } .html` ) ;
3939 let f1 = await fs . readFile ( infile , "utf-8" ) ;
40+ // any metadata on the file?
41+ const { data, content } = matter ( f1 ) ;
42+
43+ f1 = content ; // skip the frontmatter (YAML block within ---)
4044
4145 // oh the irony of removing a BOM before posting to unicode.org
4246 if ( f1 . charCodeAt ( 0 ) == 0xfeff ) {
@@ -215,6 +219,11 @@ async function renderit(infile) {
215219 a . setAttribute ( "name" , parid ) ;
216220 }
217221
222+ // If the document requests it, linkify terms
223+ if ( data . linkify ) {
224+ linkify ( dom . window . document ) ;
225+ }
226+
218227 // OK, done munging the DOM, write it out.
219228 console . log ( `Writing ${ outfile } ` ) ;
220229
@@ -246,3 +255,70 @@ fixall().then(
246255 process . exitCode = 1 ;
247256 }
248257) ;
258+
259+ function linkify ( document ) {
260+ const terms = findTerms ( document ) ;
261+ const missing = new Set ( ) ;
262+ const used = new Set ( ) ;
263+ const links = document . querySelectorAll ( "em" ) ;
264+
265+ links . forEach ( ( item ) => {
266+ const target = generateId ( item . textContent ) ;
267+ if ( terms . has ( target ) ) {
268+ const el = item . lastElementChild ?? item ;
269+ el . innerHTML = `<a href="#${ target } ">${ item . textContent } </a>` ;
270+
271+ used . add ( target ) ;
272+ } else {
273+ missing . add ( target ) ;
274+ }
275+ } ) ;
276+
277+ if ( missing . size > 0 ) {
278+ console . log ( "Potentially missing definitions:" ) ;
279+ Array . from ( missing )
280+ . sort ( )
281+ . forEach ( ( item ) => {
282+ console . log ( item ) ;
283+ } ) ;
284+ }
285+
286+ if ( terms . size === used . size ) return ;
287+ console . log ( "Some definitions were not used:" ) ;
288+ Array . from ( terms ) . forEach ( ( item ) => {
289+ if ( ! used . has ( item ) ) {
290+ console . log ( item ) ;
291+ }
292+ } ) ;
293+ }
294+
295+ function findTerms ( document ) {
296+ const terms = new Set ( ) ;
297+ let duplicateCount = 0 ;
298+ document . querySelectorAll ( "dfn" ) . forEach ( ( item ) => {
299+ const term = generateId ( item . textContent ) ;
300+ if ( term . length === 0 ) return ; // skip empty terms
301+ if ( terms . has ( term ) ) {
302+ console . log ( `Duplicate term: ${ term } ` ) ;
303+ duplicateCount ++ ;
304+ }
305+ terms . add ( term ) ;
306+ item . setAttribute ( "id" , term ) ;
307+ } ) ;
308+
309+ if ( duplicateCount > 0 ) {
310+ console . log ( "Duplicate Terms: " + duplicateCount ) ;
311+ }
312+ return terms ;
313+ }
314+
315+ function generateId ( term ) {
316+ const id = term . toLowerCase ( ) . replace ( / \s + / g, "-" ) ; // Replaces spaces safely
317+ // TODO: do better than hardcoding the one case in message-format
318+ if ( id . endsWith ( "rategies" ) ) {
319+ return id . slice ( 0 , - 3 ) + "y" ;
320+ } else if ( id . endsWith ( "s" ) && id !== "status" ) {
321+ return id . slice ( 0 , - 1 ) ;
322+ }
323+ return id ;
324+ }
0 commit comments