jjrscott

Output JSON AST directly from tsc

TypeScript:

🔍 Search Terms

“ast json” “ast output” “abstract syntax tree output”

✅ Viability Checklist

⭐ Suggestion

I am NOT a TypeScript or JavaScript developer but need to generate other languages from structures held in these languages. This is the crux of the what follows though it may not use the correct vocabulary.

Allow a TypeScript or JavaScript file to be output as a JSON abstract syntax tree directly from tsc. This would likely consist of a correctly coded version of the below script.

Note that this issue does not require the output format to be frozen, as the output from the command could itself be defined to be correct. While users of this functionality (such as myself) may have to change our downstream scripts, we would at least benefit from a known correct producer of AST JSON output.

#!/usr/bin/env node

// Original source from https://github.com/seachicken/tsparser

"use strict";

const ts = require("typescript");
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value
const getCircularReplacer = function () {
  const seen = new WeakSet();
  return function (key, value) {
    if (typeof value === "object" && value !== null) {
      if (seen.has(value)) {
        return;
      }
      seen.add(value);
    }
    return value;
  };
};

const sourceFiles = process.argv.slice(2).map((input) => {
  const program = ts.createProgram([input], { allowJs: true });
  const sourceFile = program.getSourceFile(input);
  function parse(node) {
    // https://github.com/microsoft/TypeScript/blob/1294ee8c1f37c8bf214db67e180edb3220a52236/src/compiler/types.ts#L21
    node.kindName = ts.SyntaxKind[node.kind];
    node.start = node.getStart(sourceFile);
    ts.forEachChild(node, parse);
  }
  ts.forEachChild(sourceFile, parse);
  return sourceFile;
});

try {
  process.stdout.write(JSON.stringify(sourceFiles, getCircularReplacer()));
} catch (error) {
  process.stdout.write("\n");
  process.stderr.write("".concat(error, "\n"));
}

📃 Motivating Example

I have a number of structure definitions held in TypeScript which need to be shared in other languages such as Kotlin and Go. As is often the case in these situations I have expertise only in the destination language but am required to accurately parse the source language.

đŸ’» Use Cases

  1. What do you want to use this for?
    • Exporting Typescrypt to other languages, either computational such as Swift, or a definition language such as OpenAPI.
  2. What shortcomings exist with current approaches?
    • The user often does not have the expertise to find and code the correct TypeScript solution.
  3. What workarounds are you using in the meantime?
    • The above script (which may or may not be correct)