web-dev-qa-db-fra.com

TypeScript: get arbre de syntaxe

J'avais lu "Internet entier", mais je ne trouve aucun exemple concernant l'obtention d'un arbre de syntaxe (comme dans Esprima) à partir de la source TypeScrypt. Je veux dire comment obtenir un objet comme celui-ci ( Esprima Parser Exemple)

{
    "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"
        }
    ]
}

de code javascript

var answer = 6 * 7;

uniquement pour le texte source TypeScript?

P.S. J'espère beaucoup de votre aide, parce que je ne veux pas écrire votre propre vélo terrible)

P.P.S. Je pense que les fichiers de lib TypeScript.ts (.js) et typescriptServices.ts (.js) m'aideront, mais je ne sais pas comment :(

résolu

Merci beaucoup à l'utilisateur Steve Fenton. Voici mon code, si quelqu'un est intéressé par:

// 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));
36
bukvaG

Cette question a été soulevée avant en septembre .

Il n’existe actuellement aucun moyen de le faire pour vous - il n’existe pas de méthode magique getSyntaxTree à appeler qui le fasse.

Le compilateur TypeScript est cependant open-source et écrit entièrement en TypeScript afin que vous puissiez l’analyser pour déterminer s’il ya quelque chose que vous pouvez utiliser/ajouter à un descripteur.

L'avantage de ceci est que vous avez une grande opportunité de publier votre travail en tant que projet open-source, à en juger par les votes positifs sur les deux questions, il y a une certaine demande pour cela.

Vous pouvez également récupérer l’arborescence de syntaxe à partir du code JavaScript compilé (qui est le code qui s’exécutera réellement à l’exécution) à l’aide de Esprima ou SpiderMonkey .

7
Fenton

L'analyseur TypeScript ne produit pas directement un arbre comme celui-là, mais vous pouvez toujours utiliser son modèle objet pour faire toutes sortes de choses. Nous l'utilisons dans certains outils pour effectuer des transformations de syntaxe à des fins de test, par exemple. Voici un extrait que vous pouvez utiliser pour imprimer l’arbre de syntaxe:

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
Ryan Cavanaugh

J'ai trouvé refonte fonctionne très bien. Exemple:

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

Cela produira toutes les informations nécessaires et l'événement TypeAnnotation, donc cette lib est vraiment incroyable :)

[
   {
      "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

Utiliser refonte et babylon @ next est possible. Bien que vous deviez faire confiance à la syntaxe définie par ces technologies pour représenter le code TypeScript AST et qu’elles se maintiendront à jour - puisque TypeScript propose de nouvelles fonctionnalités de langage version par version (période courte) - est pas comme les autres langages (JavaScript) pour lesquels vous avez des versions bien définies et publiées dans une norme - donc si vos utilisateurs commencent à utiliser de nouvelles fonctionnalités de langage, ces technologies (je suppose que babylon) devraient rester à jour ou l’analyse échouerait

// 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
cancerbero