1 //
   2 // Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4 //
   5 // This code is free software; you can redistribute it and/or modify it
   6 // under the terms of the GNU General Public License version 2 only, as
   7 // published by the Free Software Foundation.
   8 //
   9 // This code is distributed in the hope that it will be useful, but WITHOUT
  10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12 // version 2 for more details (a copy is included in the LICENSE file that
  13 // accompanied this code).
  14 //
  15 // You should have received a copy of the GNU General Public License version
  16 // 2 along with this work; if not, write to the Free Software Foundation,
  17 // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18 //
  19 // Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20 // or visit www.oracle.com if you need additional information or have any
  21 // questions.
  22 //
  23 
  24 //
  25 // Traverse a tree of pandoc format objects, calling callback on each
  26 // element, and replacing it if callback returns a new object.
  27 //
  28 // Inspired by the walk method in
  29 // https://github.com/jgm/pandocfilters/blob/master/pandocfilters.py
  30 //
  31 function traverse(obj, callback) {
  32     if (Array.isArray(obj)) {
  33         var processed_array = [];
  34         obj.forEach(function(elem) {
  35             if (elem === Object(elem) && elem.t) {
  36                 var replacement = callback(elem.t, elem.c || []);
  37                 if (!replacement) {
  38                     // no replacement object returned, use original
  39                     processed_array.push(traverse(elem, callback));
  40                 } else if (Array.isArray(replacement)) {
  41                     // array of objects returned, splice all elements into array
  42                     replacement.forEach(function(repl_elem) {
  43                         processed_array.push(traverse(repl_elem, callback));
  44                     })
  45                 } else {
  46                     // replacement object given, traverse it
  47                     processed_array.push(traverse(replacement, callback));
  48                 }
  49             } else {
  50                 processed_array.push(traverse(elem, callback));
  51             }
  52         })
  53         return processed_array;
  54     } else if (obj === Object(obj)) {
  55         var processed_obj = {};
  56         Object.keys(obj).forEach(function(key) {
  57             processed_obj[key] = traverse(obj[key], callback);
  58         })
  59         return processed_obj;
  60     } else {
  61         return obj;
  62     }
  63 }
  64 
  65 //
  66 // Helper constructors to create pandoc format objects
  67 //
  68 function Space() {
  69     return { 't': 'Space', 'c': [] };
  70 }
  71 
  72 function Str(value) {
  73     return { 't': 'Str', 'c': value };
  74 }
  75 
  76 function Strong(value) {
  77     return { 't': 'Strong', 'c': value };
  78 }
  79 
  80 function Header(value) {
  81     return { 't': 'Header', 'c': value };
  82 }
  83 
  84 //
  85 // Callback to change all Str texts to upper case
  86 //
  87 function uppercase(type, value) {
  88     if (type === 'Str') {
  89         return Str(value.toUpperCase());
  90     }
  91 }
  92 
  93 //
  94 // Main callback function that performs our man page AST rewrites
  95 //
  96 function manpage_filter(type, value) {
  97     // If it is a header, decrease the heading level by one, and
  98     // if it is a level 1 header, convert it to upper case.
  99     if (type === 'Header') {
 100         value[0] = Math.max(1, value[0] - 1);
 101         if (value[0] == 1) {
 102             return Header(traverse(value, uppercase));
 103         }
 104     }
 105 
 106     // Man pages does not have superscript. We use it for footnotes, so
 107     // enclose in [...] for best representation.
 108     if (type === 'Superscript') {
 109         return [ Str('['), value[0], Str(']') ];
 110     }
 111 
 112     // If it is a link, put the link name in bold. If it is an external
 113     // link, put it in brackets. Otherwise, it is either an internal link
 114     // (like "#next-heading"), or a relative link to another man page
 115     // (like "java.html"), so remove it for man pages.
 116     if (type === 'Link') {
 117         var target = value[2][0];
 118         if (target.match(/^http[s]?:/)) {
 119             return [ Strong(value[1]), Space(), Str('[' + target + ']') ];
 120         } else {
 121             return Strong(value[1]);
 122         }
 123     }
 124 }
 125 
 126 //
 127 // Main function
 128 //
 129 function main() {
 130     var input = "";
 131     while (line = readLine()) {
 132         input = input.concat(line);
 133     }
 134     var json = JSON.parse(input);
 135 
 136     var transformed_json = traverse(json, manpage_filter);
 137 
 138     print(JSON.stringify(transformed_json));
 139 }
 140 
 141 // ... and execute it
 142 main();