nvim-treesitter:在 javascript 文件中查询 jsdoc 描述
我正在为我的 neovim 插件 regexplainer 尝试测试机制。这个想法是将包含预期输出的 JSDoc 文档块放在每个查询的顶部。
/**
* @group CaptureGroups
* **0-9** (_>= 0x_)
* capture group 1:
* **0-9**
*/
/\d*(\d)/;
然后,我的测试文件将迭代该文件,从 javascript 树中获取每个正则表达式,以及注释的预期输出。然后我可以在正则表达式上运行我的插件并根据注释检查输出。
我编写了这个函数来查询文档中的注释,并使用下面的正则表达式。
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
我期望这会记录'jsdoc'语法中的标签名称和描述节点,但我实际上什么也没得到
那么我如何“查询”到嵌入的JSDoc部分树的?我尝试了此查询,但在解析查询时出现 query: invalid node type atposition 10
错误:
(comment (description) @desc) @comment
(expression_statement
(regex
(regex_pattern) @regex))
相关文件的 TSPlayground 输出如下所示:
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]
编辑:一种解决方法
我开发了此解决方法,但是这有点令人不满意,我更愿意在单个查询中获取评论的内容以及正则表达式
function M.get_regexes_with_descriptions()
local log = require'regexplainer.utils'.debug
local parsers = require "nvim-treesitter.parsers"
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 "example")
))
]])
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
I'm experimenting with a testing regime for my neovim plugin regexplainer. The idea is to put a JSDoc docblock containing the expected output on top of each query.
/**
* @group CaptureGroups
* **0-9** (_>= 0x_)
* capture group 1:
* **0-9**
*/
/\d*(\d)/;
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.
I wrote this function to query the document for comments with regexp following.
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
I expect this to log the tag name and description nodes from the 'jsdoc' grammar, but i actually get nothing
So how do I "query down" into the embedded JSDoc part of the tree? I tried this query, but got a query: invalid node type at position 10
error when parsing the query:
(comment (description) @desc) @comment
(expression_statement
(regex
(regex_pattern) @regex))
The TSPlayground output for the file in question looks like this:
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]
EDIT: A Workaround
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
function M.get_regexes_with_descriptions()
local log = require'regexplainer.utils'.debug
local parsers = require "nvim-treesitter.parsers"
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 "example")
))
]])
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论