TypeScript: obtener árbol de sintaxis


Había leído "Internet completo", pero no puedo encontrar ningún ejemplo sobre cómo obtener el árbol de sintaxis (al igual que en Esprima) de la fuente de TypeScrypt. Me refiero a cómo puedo obtener un objeto como este (Esprima Parser ejemplo)

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "answer"
                    },
                    "init": {
                        "type": "BinaryExpression",
                        "operator": "*",
                        "left": {
                            "type": "Literal",
                            "value": 6,
                            "raw": "6"
                        },
                        "right": {
                            "type": "Literal",
                            "value": 7,
                            "raw": "7"
                        }
                    }
                }
            ],
            "kind": "var"
        }
    ]
}

Desde código javascript

var answer = 6 * 7;

¿Solo para el texto fuente de TypeScript?

P.D. Espero mucho por su ayuda, porque no quiero escribir su propia bicicleta terrible)

P. P. S. Creo que los archivos lib typescript.ts(.js) y typescriptServices.ts(.js) para ayudarme, pero no sé cómo :(

Resuelto

Muchas gracias al usuario Steve Fenton. Aquí está mi código, si alguien está interesado en:

// uses
var typeScriptLS =  new Harness.TypeScriptLS();
var ServicesFactory = new Services.TypeScriptServicesFactory();
var serviceShim = ServicesFactory.createLanguageServiceShim(typeScriptLS);

// add lib.d.ts
var _libText = window.document.getElementById('lib.d.ts').innerText;
typeScriptLS.addScript('lib.d.ts', _libText.replace(/\r\n?/g,"\n"), true);

// add greeter.ts
var _sourceText = window.document.getElementById('greeter.ts').innerText;
typeScriptLS.addScript('greeter.ts', _sourceText.replace(/\r\n?/g,"\n"), true);

// script name
var _scriptName = 'greeter.ts';
// get syntax tree
var _st = serviceShim.languageService.getSyntaxTree(_scriptName);
//console.log(_st);
console.log(JSON.stringify(_st, "", 2));
Author: bukvaG, 2013-11-25

4 answers

Esta pregunta surgió antes de en septiembre.

Actualmente no hay algo que haga esto por ti - no hay un método mágico getSyntaxTree para llamar que haga esto.

El compilador de TypeScript es de código abierto, sin embargo, y está escrito completamente en TypeScript para que pueda escanearlo y averiguar si hay algo a lo que pueda usar / agregar un identificador.

El lado positivo de esto es que usted tiene una gran oportunidad para liberar su trabajo como un proyecto de código abierto como juzgar por los votos positivos sobre las dos preguntas, hay cierta demanda de esto.

Alternativamente, toma el árbol de sintaxis del JavaScript compilado (que es el código que realmente se ejecutará en tiempo de ejecución) usando Esprima o SpiderMonkey.

 7
Author: user75525,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:34

El analizador sintáctico de TypeScript no produce directamente un árbol como ese, pero aún puede usar su modelo de objetos para hacer todo tipo de cosas. Lo usamos en algunas herramientas para hacer transformaciones de sintaxis con fines de prueba, por ejemplo. Aquí hay un fragmento de código que puede usar para imprimir el árbol de sintaxis:

import ts = require('typescript');

const code = "enum { x = 1 }"
const sc = ts.createSourceFile('x.ts', code, ts.ScriptTarget.Latest, true);

let indent = 0;
function print(node: ts.Node) {
    console.log(new Array(indent + 1).join(' ') + ts.SyntaxKind[node.kind]);
    indent++;
    ts.forEachChild(node, print);
    indent--;
}

print(sc);
 12
Author: Ryan Cavanaugh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-12 14:46:59

Encontré que refundido funciona muy bien. Ejemplo:

var recast = require('recast');
var ast = recast.parse(`var answer = 6 * 7;`);
console.log(ast);

Esto generará toda la información necesaria y la anotación del tipo de evento, por lo que esta lib es realmente increíble:)

[
   {
      "type": "VariableDeclaration",
      "declarations": [
         {
            "type": "VariableDeclarator",
            "id": {
               "type": "Identifier",
               "name": "answer",
               "typeAnnotation": {
                  "type": "TypeAnnotation",
                  "typeAnnotation": {
                     "type": "NumberTypeAnnotation",
                     "loc": {
                        "start": {
                           "line": 1,
                           "column": 12
                        },
                        "end": {
                           "line": 1,
                           "column": 18
                        },
                        "lines": {},
                        "indent": 0
                     }
                  },
                  "loc": {
                     "start": {
                        "line": 1,
                        "column": 10
                     },
                     "end": {
                        "line": 1,
                        "column": 18
                     },
                     "lines": {},
                     "indent": 0
                  }
               },
               "loc": {
                  "start": {
                     "line": 1,
                     "column": 4
                  },
                  "end": {
                     "line": 1,
                     "column": 18
                  },
                  "lines": {},
                  "indent": 0
               }
            },
            "init": {
               "type": "BinaryExpression",
               "operator": "*",
               "left": {
                  "type": "Literal",
                  "value": 6,
                  "raw": "6",
                  "loc": {
                     "start": {
                        "line": 1,
                        "column": 21
                     },
                     "end": {
                        "line": 1,
                        "column": 22
                     },
                     "lines": {},
                     "indent": 0
                  }
               },
               "right": {
                  "type": "Literal",
                  "value": 7,
                  "raw": "7",
                  "loc": {
                     "start": {
                        "line": 1,
                        "column": 25
                     },
                     "end": {
                        "line": 1,
                        "column": 26
                     },
                     "lines": {},
                     "indent": 0
                  }
               },
               "loc": {
                  "start": {
                     "line": 1,
                     "column": 21
                  },
                  "end": {
                     "line": 1,
                     "column": 26
                  },
                  "lines": {},
                  "indent": 0
               }
            },
            "loc": {
               "start": {
                  "line": 1,
                  "column": 4
               },
               "end": {
                  "line": 1,
                  "column": 26
               },
               "lines": {},
               "indent": 0
            }
         }
      ],
      "kind": "var",
      "loc": {
         "start": {
            "line": 1,
            "column": 0
         },
         "end": {
            "line": 1,
            "column": 27
         },
         "lines": {},
         "indent": 0
      }
   }
]
 0
Author: Andzej Maciusovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-09 07:27:27

Usando refundición y babylon@next es posible. Aunque tendrá que confiar en la sintaxis definida por estas tecnologías para representar el código AST de TypeScript y que se mantendrán al día, ya que TypeScript tiene nuevas características de idioma versión por versión (corto período de tiempo), no es como otros idiomas (JavaScript) donde tiene versiones bien definidas y liberadas en un estándar, por lo que si sus usuarios comienzan a usar nuevas características de idioma, estas tecnologías (supongo que babylon) deben mantenerse al día hasta la fecha o el análisis fallará

// npm install recast babylon@next
const source = `
interface I {
  color: string
}
class C implements I{
  color: string='blue'
}
`
const recast = require('recast')
const tsParser = require("recast/parsers/typescript")
const ast = recast.parse(source, {
  parser: tsParser
});
console.log(`
CODE: 

${source}

AST: 

${JSON.stringify(ast)}
`);
 0
Author: cancerbero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-20 20:03:34