totaljs rede node library for chart based javascript node.js serverside-javascript control-flow call-graph

javascript - library - node rede



¿Hay alguna API estática de Call-Graph y Control-Flow-Graph para JavaScript? (8)

Aquí hay algunas soluciones que puedo ver:

  1. Usa la vista de Aptana Call Graph
    Aptana es un IDE basado en Eclipse que te permite editar y depurar el código Javascript.

  2. Usa Dynatrace
    Dynatrace es una herramienta útil que le permite rastrear su código en vivo y ver el gráfico de llamadas y los puntos importantes.

  3. Utilizar Firebug
    El famoso desarrollador addon en Firefox.

La mayoría de los gráficos de llamadas generados aquí serán dinámicos , es decir, verá el gráfico de llamadas para un conjunto determinado de acciones. Si está buscando gráficos de llamadas estáticas, verifique primero Aptana. Es posible que los gráficos de llamadas estáticas no le permitan ver llamadas dinámicas (código que se ejecuta a través de eval ()).

¿Hay generadores de Call-Graph y / o Control-Flow-Graph para JavaScript?

Call Graph - http://en.wikipedia.org/wiki/Call_graph

Gráfico de flujo de control: http://en.wikipedia.org/wiki/Control_flow_graph

EDITAR: Estoy buscando específicamente una herramienta estática que me permita acceder al gráfico utilizando algún código / API


Creo que http://doctorjs.org/ puede satisfacer sus necesidades. Tiene una buena API JSON, está disponible en github, respaldado por mozilla. Está escrito en JS en sí mismo y generalmente hace las cosas bastante bien (incluyendo el tratamiento con polimorfismo, etc.).


En general no es posible hacer esto. La razón es que las funciones son de primera clase y se escriben dinámicamente, por ejemplo:

var xs = some_function(); var each = another_function(); xs.map(each);

Hay dos incógnitas. Una es la versión del ''mapa'' que se llama (ya que el polimorfismo de Javascript no se puede resolver de forma estática en el caso general), y la otra es el valor asignado a ''cada uno'', que tampoco se puede resolver de forma estática. Las únicas propiedades estáticas de este código son que se llama a algún método de "mapa" en alguna función que obtuvimos de "another_function".

Sin embargo, si es suficiente información, hay dos recursos que podrían ser útiles. Uno es un analizador de Javascript de uso general, especialmente creado con combinadores de analizadores (el jsparse de Chris Double es bueno). Esto le permitirá anotar el árbol de análisis a medida que se está construyendo, y puede agregar una regla personalizada a los nodos de invocación para registrar los bordes del gráfico.

La otra herramienta que podría encontrar útil (un conector descarado) es un compilador de Javascript a Javascript que escribí llamado Caterwaul. Le permite hacer una comparación de patrones con los árboles de sintaxis y sabe cómo caminar sobre ellos, lo que podría ser útil en su caso. También podría ayudar si quisiera crear una traza dinámica a partir de la ejecución a corto plazo (probablemente su mejor apuesta si desea un resultado preciso y detallado).


Lo más cercano a un gráfico de llamadas es manipular un AST de Javascript completo. Esto es posible con Rhino, eche un vistazo a este artículo: http://tagneto.blogspot.com/2010/03/requirejs-kicking-some-ast.html

Ejemplo de la publicación:

//Set up shortcut to long Java package name, //and create a Compiler instance. var jscomp = Packages.com.google.javascript.jscomp, compiler = new jscomp.Compiler(), //The parse method returns an AST. //astRoot is a kind of Node for the AST. //Comments are not present as nodes in the AST. astRoot = compiler.parse(jsSourceFile), node = astRoot.getChildAtIndex(0); //Use Node methods to get child nodes, and their types. if (node.getChildAtIndex(1).getFirstChild().getType() === CALL) { //Convert this call node and its children to JS source. //This generated source does not have comments and //may not be space-formatted exactly the same as the input //source var codeBuilder = new jscomp.Compiler.CodeBuilder(); compiler.toSource(codeBuilder, 1, node); //Return the JavaScript source. //Need to use String() to convert the Java String //to a JavaScript String. return String(codeBuilder.toString()); }

Ya sea en Javascript o en Java, puede caminar el AST para construir cualquier tipo de gráfico de llamadas o cadena de dependencia que desee.


No relacionado directamente con NodeJS, pero generalmente con JavaScript, SAP ha lanzado un IDE web relacionado con HANA (pero también se puede acceder a él desde la nube de HANA; consulte más detalles aquí http://scn.sap.com/community/developer-center/cloud-platform/blog/2014/04/15/sap-hana-web-ide-online-tutorial ).

En este IDE web, hay un servicio basado en REST que analiza el contenido de JavaScript con un enfoque principal (pero no solo) en la creación de un gráfico de llamadas. Hay muchos consumidores de ese servicio, como Code Navigation.

Más información aquí (consulte la sección Flujo de funciones): http://scn.sap.com/community/developer-center/hana/blog/2014/12/02/sap-hana-sps-09-new-developer-features-sap-hana-web-based-development-workbench

Nota: Soy el desarrollador principal de este servicio.


Para hacer esto, necesitas:

  • analizando
  • resolución de nombres (manejo del alcance)
  • análisis de tipo (aunque se puede decir que JavaScript está "tipificado dinámicamente", hay todo tipo de constantes tipadas, incluidas las constantes de función que son de interés específico aquí)
  • análisis de flujo de control (para construir la estructura de los gráficos de flujo de control dentro de los métodos)
  • análisis de flujo de datos (para rastrear dónde se generan / usan esos tipos)
  • lo que equivale a un análisis global de punto a punto (para rastrear las constantes de función pasadas entre funciones como valores a un punto de aplicación).

La forma de hacerlo está bastante bien documentada en la literatura del compilador. Sin embargo, implementar esta cuestión de sudor considerable, por lo que las respuestas de la forma de "puede usar un resultado del analizador para obtener lo que desea" en lugar de perder el punto.

Si pudiera aplicar toda esta maquinaria, lo que obtendrá como resultado práctico es una respuesta conservadora , por ejemplo, "A puede llamar a B". Esto es todo lo que sabes de todos modos, considera

void A(int x,y) { if (x>y) foo.B(); }

Debido a que una herramienta en algún momento simplemente no puede razonar acerca de lógica compleja, puede obtener "A puede llamar B" incluso cuando el diseñador de la aplicación sabe que no es posible:

void A(int x) // programmer asserts x<4 { if (x>5) foo.B(); }

eval hace que el problema empeore, porque necesita hacer un seguimiento de los resultados de valor de cadena que llegan a los comandos eval y analizarlos para obtener algún tipo de pista sobre qué código se está evaluando y qué funciones puede llamar el código evaluado. Las cosas se ponen realmente feas si alguien pasa "eval" en una cadena a eval: - {También es probable que necesite modelar el contexto de ejecución del programa; Sospecho que hay muchas API de navegador que incluyen devoluciones de llamada.

Si alguien le ofrece una herramienta que tiene toda la maquinaria necesaria completamente configurada para resolver su problema de manera inmediata, obviamente sería genial. Mi sospecha es que no obtendrás tal oferta, porque tal herramienta no existe. La razón es toda la infraestructura necesaria; es difícil de construir y casi nadie puede justificarlo con solo una herramienta. Incluso un "compilador de JavaScript optimizado" si puede encontrar uno, probablemente no tendrá toda esta maquinaria, especialmente el análisis global, y es poco probable que lo que tiene esté empaquetado en una forma diseñada para un fácil consumo para su propósito.

He estado ganándome la cabeza en este problema desde que comencé a programar en 1969 (algunos de mis programas en ese entonces eran compiladores y quería todo esto). La única forma de obtener esto es amortizar el costo de toda esta maquinaria en muchas herramientas.

Mi compañía ofrece el kit de herramientas de reingeniería de software DMS , un paquete de maquinaria genérica de análisis y transformación de compiladores, con una variedad de front-ends de idiomas de computadora con potencia industrial (incluidos C, C ++, COBOL y sí, JavaScript). DMS ofrece API para permitir que se construyan herramientas personalizadas sobre sus bases genéricas.

La maquinaria genérica que aparece en la parte superior del mensaje está presente en DMS, incluido el gráfico de flujo de control y el análisis de flujo de datos disponibles a través de una API documentada. Ese análisis de flujo tiene que estar vinculado a los frontales específicos del lenguaje. Eso también requiere algo de trabajo, por lo que aún no lo hemos hecho para todos los idiomas. Hemos hecho esto para C [probado en sistemas de 18,000 unidades de compilación como un monolito, incluyendo el cálculo del gráfico de llamadas para las 250,000 funciones presentes, incluyendo llamadas de funciones indirectas], COBOL y Java y estamos trabajando en C ++.

El DMS tiene la misma respuesta del analizador "JavaScript" que otras respuestas en este hilo, y visto desde esa perspectiva, el DMS no es mejor que las otras respuestas que dicen "construirlo sobre un analizador". La distinción debe ser clara: la maquinaria ya está presente en DMS, por lo que el trabajo no consiste en implementar la maquinaria y vincularla al analizador; Simplemente lo está vinculando al analizador. Esto todavía es un poco de trabajo, pero mucho menos que si solo comenzaras con un analizador.


Para un enfoque de js, echa un vistazo a los arguments.callee.caller . Le brinda la función que llamó a la función en la que se encuentra y puede realizar la pila de llamadas. Hay un ejemplo en este hilo http://bytes.com/topic/javascript/answers/470251-recursive-functions-arguments-callee-caller .

Tenga en cuenta que es posible que esto no funcione en todos los navegadores y que se encuentre con algunas cosas inesperadas cuando llegue a la parte superior de la "pila de llamadas" o funciones nativas, así que úselo bajo su propio riesgo.

Mi propio ejemplo funciona en IE9 y Chrome 10 (no probé ningún otro navegador).

<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body onload="Function1()"> <form id="form1" runat="server"> <div> </div> </form> </body> <script type="text/javascript"> function Function1() { Function2(); } function Function2() { Function3(); } function Function3() { Function4(); } function Function4() { var caller = arguments.callee.caller; var stack = []; while (caller != null) { stack.push(caller);//this is the text of the function. You can probably write some code to parse out the name and parameters. var args = caller.arguments; //this is the arguments for that function. You can get the actual values here and do something with them if you want. caller = caller.caller; } alert(stack); } </script> </html>


WALA es un marco de análisis de programa de código abierto que puede crear gráficos de llamadas estáticas y gráficos de flujo de control para JavaScript:

http://wala.sourceforge.net/wiki/index.php/Main_Page

Una advertencia es que a las gráficas de llamadas les pueden faltar algunos bordes en presencia de eval , with otras construcciones difíciles de analizar. Además, todavía estamos trabajando en la escalabilidad; WALA aún no puede analizar jquery en un tiempo razonable, pero se pueden analizar algunos otros marcos. Además, nuestra documentación para crear gráficos de llamadas de JavaScript no es excelente en este momento (mejorarla está en mi lista de tareas pendientes).

Estamos trabajando activamente en este código, por lo que si lo intenta y tiene problemas, puede enviar un correo electrónico a la lista de correo de WALA ( https://lists.sourceforge.net/lists/listinfo/wala-wala ) o contactarme.