javascriptnode.jsabstract-syntax-treetreesitter

How to get the tree structure data of class/property/method in tree-sitter?


How to get the tree structure data of class/property/method in tree-sitter:

I can only match the class like below:

const Parser = require("tree-sitter")
const JavaScript = require("tree-sitter-javascript")
const { Query } = Parser 


const parser = new Parser()
parser.setLanguage(JavaScript)

const query = new Query(
  JavaScript,
  `
    (class_declaration name: (identifier) @class-name)
  `
);


const tree = parser.parse(`
class Person {}
 
const TestPerson = class {}

class Person2 {}
 
const TestPerson2 = class {}
  `);
const matches = query.matches(tree.rootNode);

matches.forEach(item => {
  console.log(item.captures[0])
})

there I can get the classnames of a file.

but you see the GitHub page: I want to get the tree structure data of AST:

enter image description here

1、please help with how to match the AST tree data?
2、you see the snapshot display a 3-layer depth tree data, how to control the matched tree data depth?


Solution

  • Normally, this is usally achieved by programmatically iterate through the syntax tree instead of direct matching. If you really want go matching, then I think the answer by @Prabhat is the one for you.

    If you want alternative way by iterating the AST, here's the solution:

    const Parser = require('tree-sitter');
    const JavaScript = require('tree-sitter-javascript');
    
    const parser = new Parser();
    parser.setLanguage(JavaScript);
    
    const code = `INSERT YOUR CODE HERE`;
    
    // Parse the JavaScript code
    const tree = parser.parse(code);
    
    // AST type to readable name map
    const treeTypeNameMap = {
        "class_declaration": "class",
        "method_definition": "method",
        "function_declaration": "function"
    }
    
    // Nodes that we consider to increment the depth level.
    // For example, when we enter a new class body, or new statement block.
    const depthNodes = [
        "class_body", "statement_block"
    ];
    
    // Recursively traverse the syntax tree up to a certain depth
    function findClassesAndMethods(node, currentDepth = 0, maxDepth = 3) {
        // If we reached the maximum depth, return
        if (currentDepth >= maxDepth) {
            return;
        }
    
        let nextDepth = currentDepth;
        // Only increment depth level if we encounter a new class body or statement block
        if (depthNodes.includes(node.type)) {
            nextDepth += 1;
        } else if (node.type in treeTypeNameMap) {
            const name = node.childForFieldName("name").text;
            console.log("-".repeat(currentDepth), treeTypeNameMap[node.type], name);
        }
    
        node.children.forEach(child => findClassesAndMethods(child, nextDepth, maxDepth))
    }
    
    // Start traversing from the root node
    findClassesAndMethods(tree.rootNode);
    

    Example input:

    class C {
        A() {
            {
                class AInner {}
            }
            class B {
                
            }
        }
    }
    
    class A {
        constructor() {}
        B() {
            class C {
                
            }
        }
    }
    

    And its output:

     class C
    - method A
    -- class B
     class A
    - method constructor
    - method B
    -- class C