cli.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #!/usr/bin/env node
  2. // Simple CLI for KaTeX.
  3. // Reads TeX from stdin, outputs HTML to stdout.
  4. // To run this from the repository, you must first build KaTeX by running
  5. // `yarn` and `yarn build`.
  6. /* eslint no-console:0 */
  7. let katex;
  8. try {
  9. katex = require("./");
  10. } catch (e) {
  11. console.error(
  12. "KaTeX could not import, likely because dist/katex.js is missing.");
  13. console.error("Please run 'yarn' and 'yarn build' before running");
  14. console.error("cli.js from the KaTeX repository.");
  15. console.error();
  16. throw e;
  17. }
  18. const {version} = require("./package.json");
  19. const fs = require("fs");
  20. const program = require("commander")
  21. .version(version)
  22. .option("-d, --display-mode",
  23. "Render math in display mode, which puts the math in display style " +
  24. "(so \\int and \\sum are large, for example), and centers the math " +
  25. "on the page on its own line.")
  26. .option("-t, --no-throw-on-error",
  27. "Render errors (in the color given by --error-color) instead of " +
  28. "throwing a ParseError exception when encountering an error.")
  29. .option("-c, --error-color <color>",
  30. "A color string given in the format 'rgb' or 'rrggbb' (no #). " +
  31. "This option determines the color of errors rendered by the -t option.",
  32. "#cc0000",
  33. (color) => "#" + color)
  34. .option("-b, --color-is-text-color",
  35. "Makes \\color behave like LaTeX's 2-argument \\textcolor, " +
  36. "instead of LaTeX's one-argument \\color mode change.")
  37. .option("-S, --strict",
  38. "Turn on strict / LaTeX faithfulness mode, which throws an error " +
  39. "if the input uses features that are not supported by LaTeX")
  40. .option("-s, --max-size <n>",
  41. "If non-zero, all user-specified sizes, e.g. in " +
  42. "\\rule{500em}{500em}, will be capped to maxSize ems. " +
  43. "Otherwise, elements and spaces can be arbitrarily large",
  44. Infinity, parseInt)
  45. .option("-e, --max-expand <n>",
  46. "Limit the number of macro expansions to the specified number, to " +
  47. "prevent e.g. infinite macro loops. If set to Infinity, the macro " +
  48. "expander will try to fully expand as in LaTeX.",
  49. (n) => (n === "Infinity" ? Infinity : parseInt(n)))
  50. .option("-m, --macro <def>",
  51. "Define custom macro of the form '\\foo:expansion' (use multiple -m " +
  52. "arguments for multiple macros).",
  53. (def, defs) => {
  54. defs.push(def);
  55. return defs;
  56. }, [])
  57. .option("-f, --macro-file <path>",
  58. "Read macro definitions, one per line, from the given file.")
  59. .option("-i, --input <path>", "Read LaTeX input from the given file.")
  60. .option("-o, --output <path>", "Write html output to the given file.");
  61. if (require.main !== module) {
  62. module.exports = program;
  63. return;
  64. }
  65. const options = program.parse(process.argv);
  66. function readMacros() {
  67. if (options.macroFile) {
  68. fs.readFile(options.macroFile, "utf-8", function(err, data) {
  69. if (err) {throw err;}
  70. splitMacros(data.toString().split('\n'));
  71. });
  72. } else {
  73. splitMacros([]);
  74. }
  75. }
  76. function splitMacros(macroStrings) {
  77. // Override macros from macro file (if any)
  78. // with macros from command line (if any)
  79. macroStrings = macroStrings.concat(options.macro);
  80. const macros = {};
  81. for (const m of macroStrings) {
  82. const i = m.search(":");
  83. if (i !== -1) {
  84. macros[m.substring(0, i).trim()] = m.substring(i + 1).trim();
  85. }
  86. }
  87. options.macros = macros;
  88. readInput();
  89. }
  90. function readInput() {
  91. let input = "";
  92. if (options.input) {
  93. fs.readFile(options.input, "utf-8", function(err, data) {
  94. if (err) {throw err;}
  95. input = data.toString();
  96. writeOutput(input);
  97. });
  98. } else {
  99. process.stdin.on("data", function(chunk) {
  100. input += chunk.toString();
  101. });
  102. process.stdin.on("end", function() {
  103. writeOutput(input);
  104. });
  105. }
  106. }
  107. function writeOutput(input) {
  108. const output = katex.renderToString(input, options) + "\n";
  109. if (options.output) {
  110. fs.writeFile(options.output, output, function(err) {
  111. if (err) {
  112. return console.log(err);
  113. }
  114. });
  115. } else {
  116. console.log(output);
  117. }
  118. }
  119. readMacros();