Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse typescript definition to json?

I want to parse my typescript definition to json, such as

namespace call.common {
    namespace login {
        interface Request {
          userName: string;
          password: string;
        }

        interface Response {
            isLogin: boolean
        }
    }
}

the json could be something like this:

{
    namespace: "call.common.login",
    interfaces: [
        {
            "name": "Request",
            params: [{
                name: "userName",
                type: "string",
            }, {
                name: "password",
                type: "string"
            }]
        }, {
            "name": "Response",
            params: [{
                name: "isLogin",
                type: boolean
            }]
        }
    ]
}

According to the document Using-the-Compiler-API I am trying to use compiler:

function parseGrpcTypings(fileName, options) {
    var program = ts.createProgram(fileName, options);
    var checker = program.getTypeChecker();

    const sourceFile = program.getSourceFiles()[0];
    ts.forEachChild(sourceFile, visit);

    function visit(node) {
        if (!isNodeExported(node)) {
            return;
        }

        if (node.kind === ts.SyntaxKind.ModuleDeclaration) {
            ts.forEachChild(node, visit);
        } else if (node.kind === ts.SyntaxKind.InterfaceDeclaration) {
            // how to parse interface
        } else {
            // how to deal with namespace
        }
    }

    function isNodeExported(node) {
        return (node.flags & ts.NodeFlags.Export) !== 0 || (node.parent && node.parent.kind === ts.SyntaxKind.SourceFile);
    }
}

parseGrpcTypings("/tmp/test.d.ts", {
    target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
});
like image 569
roger Avatar asked Sep 20 '16 07:09

roger


People also ask

How to type JSON parse TypeScript?

Use the JSON. parse() method to parse a JSON string in TypeScript, e.g. const result: Person = JSON. parse(jsonStr) . The method parses a JSON string and returns the corresponding value.

How to get JSON value in TypeScript?

To parse a JSON string in TypeScript, you can use JSON. parse().


1 Answers

Based on your code, here is a ts2json.js module that turns .d.ts file into plain JavaScript objects:

const ts = require('typescript');

const PROPERTY_TYPES = {
    any: ts.SyntaxKind.AnyKeyword,
    boolean: ts.SyntaxKind.BooleanKeyword,
    number: ts.SyntaxKind.NumberKeyword,
    string: ts.SyntaxKind.StringKeyword,
};
class TSNode {
    constructor(name, type) {
        this.children = [];
        this.addChildren = (name, type) => {
            let node = new TSNode(name, type);
            this.children.push(node);
            return node;
        };
        this.getType = () => this.type;
        this.getObject = () => {
            let map = {};
            map[this.name] = this.children.length
                ? this.children
                      .map(child => child.getObject())
                      .reduce((pv, child) => {
                          for (let key in child) {
                              if (pv.hasOwnProperty(key) || key in pv) {
                                  Object.assign(pv[key], child[key]);
                              } else {
                                  pv[key] = child[key];
                              }
                          }
                          return pv;
                      }, {})
                : this.type;
            return map;
        };
        this.name = name;
        this.type = type;
    }
}
let visit = parent => node => {
    switch (node.kind) {
        case ts.SyntaxKind.ModuleDeclaration:
            let moduleName = node.name.text;
            ts.forEachChild(node, visit(parent.addChildren(moduleName)));
            break;
        case ts.SyntaxKind.ModuleBlock:
            ts.forEachChild(node, visit(parent));
            break;
        case ts.SyntaxKind.InterfaceDeclaration:
            let interfaceName = node.name.text;
            parent[interfaceName] = {};
            // console.log('interface');
            ts.forEachChild(node, visit(parent.addChildren(interfaceName)));
            break;
        case ts.SyntaxKind.PropertySignature:
            let propertyName = node.name;
            let propertyType = node.type;
            let arrayDeep = 0;
            let realPropertyName =
                'string' !== typeof propertyName && 'text' in propertyName
                    ? propertyName.text
                    : propertyName;
            while (propertyType.kind === ts.SyntaxKind.ArrayType) {
                arrayDeep++;
                propertyType = propertyType.elementType;
            }
            if (propertyType.kind === ts.SyntaxKind.TypeReference) {
                let realPropertyType = propertyType.typeName;
                parent.addChildren(
                    realPropertyName,
                    'Array<'.repeat(arrayDeep) +
                        (realPropertyType.kind === ts.SyntaxKind.QualifiedName
                            ? realPropertyType.getText()
                            : 'text' in realPropertyType
                              ? realPropertyType.text
                              : realPropertyType) +
                        '>'.repeat(arrayDeep)
                );
            } else {
                for (let type in PROPERTY_TYPES) {
                    if (propertyType.kind === PROPERTY_TYPES[type]) {
                        parent.addChildren(realPropertyName, type);
                        break;
                    }
                }
            }
            break;
        default:
    }
};

module.exports = function(filename, options) {
    const ROOT_NAME = 'root';
    const node = new TSNode(ROOT_NAME);

    let program = ts.createProgram([filename], options);
    let checker = program.getTypeChecker();
    let sourceFile = program.getSourceFiles()[1];

    ts.forEachChild(sourceFile, visit(node));

    return node.getObject()[ROOT_NAME];
};

You can get the JSON string with JSON.stringify method. The following TypeScript definition file eg.d.ts:

declare namespace School.Users {
    interface User {
        lastName: string;
        firstName: string;
        email: string;
    }

    interface Student extends User {
        graduation: number;
        mainTeacher: Teacher;
    }

    interface Teacher extends User {
        classes: Student[][];
        room: School.Building.Room;
    }
}

declare namespace School.Building {
    interface Room {
        name: string;
    }
}

Can be parsed to JSON with the following:

node -e "console.log(JSON.stringify(require('./ts2json.js')('./eg.d.ts', {}), null, '\t'))"

That outputs:

{
    "School": {
        "Users": {
            "User": {
                "lastName": "string",
                "firstName": "string",
                "email": "string"
            },
            "Student": {
                "graduation": "number",
                "mainTeacher": "Teacher"
            },
            "Teacher": {
                "classes": "Array<Array<Student>>",
                "room": "School.Building.Room"
            }
        },
        "Building": {
            "Room": {
                "name": "string"
            }
        }
    }
}
like image 125
Antoine du Hamel Avatar answered Oct 12 '22 22:10

Antoine du Hamel