title: nvim-treesitter: query for jsdoc description within javascript file
body: <p>I'm experimenting with a testing regime for my neovim plugin <a href="https://github.com/bennypowers/nvim-regexplainer" rel="nofollow noreferrer">regexplainer</a>. The idea is to put a JSDoc docblock containing the expected output on top of each query.</p>
  <pre class="lang-js prettyprint-override"><code>/** 
   * @group CaptureGroups
   * **0-9** (_&gt;= 0x_)
   * capture group 1:
   *   **0-9**
   */
  /\d*(\d)/;
  </code></pre>
  <p>My test file would then iterate through the file, getting each regex from the javascript tree, along with it's expected output from the comment. I could then run my plugin on the regexp and check the output against the comment.</p>
  <p>I wrote this function to query the document for comments with regexp following.</p>
  <pre class="lang-lua prettyprint-override"><code>function M.get_regexes_with_descriptions()
    local log = require'regexplainer.utils'.debug
  
    local query_js = vim.treesitter.query.parse_query('javascript', [[
      (comment) @comment
      (expression_statement
        (regex
          (regex_pattern) @regex))
    ]])
  
    local query_jsdoc = vim.treesitter.query.parse_query('jsdoc', [[
      (tag_name) @tag_name
      (description) @description
    ]])
  
    local parser = vim.treesitter.get_parser(0, 'javascript')
  
    local tree, other = unpack(parser:parse())
  
    for id, node, metadata in query_js:iter_captures(tree:root(), 0) do
      local name = query_js.captures[id] -- name of the capture in the query
      if node:type() == 'comment' then
        for cid, cnode, cmetadata in node:iter_children() do
          local cname = query_jsdoc.captures[cid] -- name of the capture in the query
          log(get_info_on_capture(cid, cnode, cname, cmetadata))
        end
      end
    end
  end
  </code></pre>
  <p>I <strong>expect</strong> this to log the tag name and description nodes from the 'jsdoc' grammar, but i <strong>actually</strong> get nothing</p>
  <p>So how do I &quot;query down&quot; into the embedded JSDoc part of the tree? I tried this query, but got a <code>query: invalid node type at position 10</code> error when parsing the query:</p>
  <pre class="lang-lisp prettyprint-override"><code>(comment (description) @desc) @comment
  (expression_statement
    (regex
      (regex_pattern) @regex))
  </code></pre>
  <p>The TSPlayground output for the file in question looks like this:</p>
  <pre><code>comment [0, 0] - [5, 3]
    tag [1, 3] - [4, 12]
      tag_name [1, 3] - [1, 9]
      description [1, 10] - [4, 12]
  expression_statement [6, 0] - [6, 10]
    regex [6, 0] - [6, 9]
      pattern: regex_pattern [6, 1] - [6, 8]
        term [6, 1] - [6, 8]
          character_class_escape [6, 1] - [6, 3]
          zero_or_more [6, 3] - [6, 4]
          anonymous_capturing_group [6, 4] - [6, 8]
            pattern [6, 5] - [6, 7]
              term [6, 5] - [6, 7]
                character_class_escape [6, 5] - [6, 7]
  </code></pre>
  <h2>EDIT: A Workaround</h2>
  <p>I developed this workaround but it's a bit unsatisfying, I'd prefer to get the comment's contents along with the regexp in a single query</p>
  <pre class="lang-lua prettyprint-override"><code>function M.get_regexes_with_descriptions()
    local log = require'regexplainer.utils'.debug
    local parsers = require &quot;nvim-treesitter.parsers&quot;
  
    local query_js = vim.treesitter.query.parse_query('javascript', [[
      (expression_statement
        (regex
          (regex_pattern) @regex)) @expr
      ]])
  
    local query_jsdoc = vim.treesitter.query.parse_query('jsdoc', [[
      (tag
        (tag_name) @tag_name
        ((description) @description
        ;; (#eq? @tag_name &quot;example&quot;)
        ))
    ]])
  
    local parser = parsers.get_parser(0)
  
    local tree = unpack(parser:parse())
  
    local caps = {}
  
    for id, node in query_js:iter_captures(tree:root(), 0) do
      local cap = {}
      local name = query_js.captures[id] -- name of the capture in the query
      log(id, name, ts_utils.get_node_text(node))
      if name == 'expr' then
        cap.regex = node:named_child('pattern')
        cap.comment = node:prev_sibling()
        table.insert(caps, cap)
      end
  
    end
  
    local results = {}
  
    for _, cap in ipairs(caps) do
      local result = {}
      result.text = ts_utils.get_node_text(cap.regex)
  
      local comment_str = table.concat(ts_utils.get_node_text(cap.comment), '\n')
      local jsdoc_parser = vim.treesitter.get_string_parser(comment_str, 'jsdoc')
      local jsdoc_tree = jsdoc_parser:parse()[1]
  
      for id, ch, metadata in query_jsdoc:iter_captures(jsdoc_tree:root()) do
        if query_jsdoc.captures[id] == 'description' then
          result.description = table.concat(
            vim.tbl_map(function(line)
              return line:gsub('^%s+%*', '')
            end, ts_utils.get_node_text(ch)), '\n')
        end
      end
      table.insert(results, result)
    end
  
    return results
  end
  </code></pre>