astexplorer icon indicating copy to clipboard operation
astexplorer copied to clipboard

Feature request: Tree of JavaScript scopes (eslint-scope)

Open ajvincent opened this issue 5 years ago • 5 comments

https://github.com/eslint/eslint-scope

I'm thinking about using eslint-scope in one of my projects, but I need a visualization of its output to be sure that's what I'm looking for.

Can someone help me out, please?

ajvincent avatar Jun 04 '20 08:06 ajvincent

This sounds interesting but I'm not sure how such a visualization would look like. What did you have in mind?

fkling avatar Jun 19 '20 18:06 fkling

I think the tree root would be a global scope object, with child objects being child scopes and the variables in each scope (AST objects). var currentScope = scopeManager.acquire(ast); // global scope

ajvincent avatar Jun 19 '20 19:06 ajvincent

Would you expect it to be rendered like we currently render the AST (like an object with properties), or something else?

fkling avatar Sep 11 '20 06:09 fkling

As similarly as possible, yes. I'm really not expecting major changes in the appearance.

ajvincent avatar Sep 12 '20 16:09 ajvincent

Stumbled across this issue today and figured some of the following notes/references from some research i've been doing lately might be relevant/helpful here:

  • https://github.com/estools/escope
    • Escope: ECMAScript scope analyzer

    • https://github.com/mazurov/escope-demo
      • Escope library: Scope Objects Visualization

      • https://mazurov.github.io/escope-demo/
      • https://github.com/lizhihao132/escope-demo/
        • Scope Objects Visualization (By Esprima, Acorn, escope, eslint-scope)

        • Note: This is a fork of the original escope-demo repo that seems to add new features/etc
        • https://lizhihao132.github.io/escope-demo/
    • https://github.com/mazurov/eslevels
      • ECMAScript scope levels analyzer based on escope library

      • ECMAScript scope levels analyzer based on escope library. The original purpose of this library is to enable scope context coloring in javascript editors (for SublimeText in first order).

      • https://github.com/mazurov/eslevels-demo
        • JavaScript scope coloring based on esprima toolbox

        • This is a simple web application created to show features of eslevels javascript library — am ECMAScript scope levels analyzer based on escope library which original purpose was to enable scope context coloring in javascript editors (SublimeText in first order).

        • https://mazurov.github.io/eslevels-demo/
      • https://github.com/mazurov/sublime-levels
        • SublimeText plugin for scope context coloring (ST2/ST3)

Of particular note are the demo's for escope and eslevels; and the forked escope demo that also seems to add support for eslint-scope:

  • escope: https://mazurov.github.io/escope-demo/
    • image
  • eslevels: https://mazurov.github.io/eslevels-demo/
    • image
  • eslint-scope: https://lizhihao132.github.io/escope-demo/
    • image

While I wouldn't say that any of these tools represent an optimal UX for my personal needs/desires, they definitely take steps in the right direction!


Then to add my personal /2c to this as well, it would be nice to be able to view the scopes from any number of compatible tools/parsers. For example I am currently working with Babel's parser, and it seems to have built in scope handling, so it would be great to be able to visualise that.

Here's a link to some super hacky explorative code i've been playing with lately:

  • https://replit.com/@0xdevalias/Rewriting-JavaScript-Variables-via-AST-Examples#babel_v1_3_clean.js

But within that we can see how the scopes can be viewed:

image

Which is output from this snippet of code:

// Source: https://replit.com/@0xdevalias/Rewriting-JavaScript-Variables-via-AST-Examples#babel_v1_3_clean.js

const debugLogScopeBindings = ({ path }) => {
  if (!DEBUG) return

  const debugLog = makeDebugLog(path);

  const scopeBindings = path.scope.bindings;
  const allBindings = path.scope.getAllBindings();

  const nameFromPath = getNameFromPath(path);

  console.group(`[DEBUG] Path (type=${path.type}, nameFromPath=${nameFromPath}, pathLocation=${path.getPathLocation()})`);

  console.group('Code');

  console.log(path.toString().slice(0, MAX_CODE_CONTEXT_LENGTH));

  console.groupEnd();

  console.group(`Scope Dump (uid=${path.scope.uid})`);

  path.scope.dump();

  console.groupEnd();

  console.group('Scope Bindings');

  console.table(
    Object.entries(scopeBindings).map(([bindingName, binding]) => {
      return {
        name: bindingName,
        kind: binding.kind,
        references: binding.references,
        scopeUid: binding.scope.uid,
        scopeType: binding.scope.path.type,
      }
    })
  );

  console.groupEnd();

  console.group('All Bindings');

  console.table(
    Object.entries(allBindings).map(([bindingName, binding]) => {
      return {
        name: bindingName,
        kind: binding.kind,
        references: binding.references,
        scopeUid: binding.scope.uid,
        scopeType: binding.scope.path.type,
      }
    })
  );

  console.groupEnd();

  // ..snip..

  console.groupEnd();
}

0xdevalias avatar Jul 10 '23 02:07 0xdevalias