3636 "type_declaration" ,
3737 "type_spec" ,
3838 },
39+ # @JSONC Scope Node Types, IMPL_JSONC_2, impl, [FE_JSONC]
40+ CommentType .jsonc : {"pair" , "object" , "array" , "document" },
3941}
4042
4143logger = get_logger (__name__ )
6567GO_QUERY = """
6668 (comment) @comment
6769"""
70+ JSONC_QUERY = """(comment) @comment"""
71+
72+ # JSON value node types that can be associated with a comment.
73+ JSON_STRUCTURE_TYPES = {
74+ "pair" ,
75+ "object" ,
76+ "array" ,
77+ "string" ,
78+ "number" ,
79+ "true" ,
80+ "false" ,
81+ "null" ,
82+ }
6883
6984
7085def is_text_file (filepath : Path , sample_size : int = 2048 ) -> bool :
@@ -82,7 +97,7 @@ def is_text_file(filepath: Path, sample_size: int = 2048) -> bool:
8297 return False
8398
8499
85- # @Tree-sitter parser initialization for multiple languages, IMPL_LANG_1, impl, [FE_C_SUPPORT, FE_CPP, FE_PY, FE_YAML, FE_RUST, FE_GO]
100+ # @Tree-sitter parser initialization for multiple languages, IMPL_LANG_1, impl, [FE_C_SUPPORT, FE_CPP, FE_PY, FE_YAML, FE_RUST, FE_GO, FE_JSONC ]
86101def init_tree_sitter (comment_type : CommentType ) -> tuple [Parser , Query ]:
87102 if comment_type == CommentType .cpp :
88103 import tree_sitter_cpp # noqa: PLC0415
@@ -114,6 +129,11 @@ def init_tree_sitter(comment_type: CommentType) -> tuple[Parser, Query]:
114129
115130 parsed_language = Language (tree_sitter_go .language ())
116131 query = Query (parsed_language , GO_QUERY )
132+ elif comment_type == CommentType .jsonc :
133+ import tree_sitter_json # noqa: PLC0415
134+
135+ parsed_language = Language (tree_sitter_json .language ())
136+ query = Query (parsed_language , JSONC_QUERY )
117137 else :
118138 raise ValueError (f"Unsupported comment style: { comment_type } " )
119139 parser = Parser (parsed_language )
@@ -213,8 +233,11 @@ def find_yaml_next_structure(node: TreeSitterNode) -> TreeSitterNode | None:
213233 return None
214234
215235
216- def find_yaml_prev_sibling_on_same_row (node : TreeSitterNode ) -> TreeSitterNode | None :
217- """Find a previous named sibling that is on the same row as the comment."""
236+ def find_prev_sibling_on_same_row (node : TreeSitterNode ) -> TreeSitterNode | None :
237+ """Find a previous named sibling that is on the same row as the comment.
238+
239+ Grammar-agnostic: used to detect inline comments in both YAML and JSONC.
240+ """
218241 comment_row = node .start_point .row
219242 current = node .prev_named_sibling
220243
@@ -235,7 +258,7 @@ def find_yaml_prev_sibling_on_same_row(node: TreeSitterNode) -> TreeSitterNode |
235258def find_yaml_associated_structure (node : TreeSitterNode ) -> TreeSitterNode | None :
236259 """Find the YAML structure (key-value pair, list item, etc.) associated with a comment."""
237260 # First, check if this is an inline comment by looking for a previous sibling on the same row
238- prev_sibling_same_row = find_yaml_prev_sibling_on_same_row (node )
261+ prev_sibling_same_row = find_prev_sibling_on_same_row (node )
239262 if prev_sibling_same_row :
240263 return prev_sibling_same_row
241264
@@ -254,6 +277,35 @@ def find_yaml_associated_structure(node: TreeSitterNode) -> TreeSitterNode | Non
254277 return None
255278
256279
280+ def find_jsonc_associated_structure (node : TreeSitterNode ) -> TreeSitterNode | None :
281+ """Find the JSON structure (key/value pair, value, list item) for a comment.
282+
283+ JSON is data rather than code, so association follows the same intent as YAML:
284+ an inline comment belongs to the value on its row, a leading comment belongs to
285+ the following structure, otherwise it belongs to the enclosing structure.
286+ """
287+ # Inline comment: a value/pair on the same row, before the comment
288+ prev_sibling_same_row = find_prev_sibling_on_same_row (node )
289+ if prev_sibling_same_row :
290+ return prev_sibling_same_row
291+
292+ # Leading comment: the next structure following the comment
293+ current = node .next_named_sibling
294+ while current :
295+ if current .type in JSON_STRUCTURE_TYPES :
296+ return current
297+ current = current .next_named_sibling
298+
299+ # Otherwise: the enclosing structure
300+ parent = node .parent
301+ while parent :
302+ if parent .type in {"pair" , "object" , "array" }:
303+ return parent
304+ parent = parent .parent
305+
306+ return None
307+
308+
257309def find_associated_scope (
258310 node : TreeSitterNode , comment_type : CommentType = CommentType .cpp
259311) -> TreeSitterNode | None :
@@ -262,6 +314,10 @@ def find_associated_scope(
262314 # YAML uses different structure association logic
263315 return find_yaml_associated_structure (node )
264316
317+ if comment_type == CommentType .jsonc :
318+ # JSONC uses data-aware structure association logic
319+ return find_jsonc_associated_structure (node )
320+
265321 if node .type == CommentCategory .docstring :
266322 # Only for python's docstring
267323 return find_enclosing_scope (node , comment_type )
0 commit comments