2929 "trait_item" ,
3030 "mod_item" ,
3131 },
32+ # @JSONC Scope Node Types, IMPL_JSONC_2, impl, [FE_JSONC]
33+ CommentType .jsonc : {"pair" , "object" , "array" , "document" },
3234}
3335
3436# initialize logger
6062 (line_comment) @comment
6163 (block_comment) @comment
6264"""
65+ JSONC_QUERY = """(comment) @comment"""
66+
67+ # JSON value node types that can be associated with a comment.
68+ JSON_STRUCTURE_TYPES = {
69+ "pair" ,
70+ "object" ,
71+ "array" ,
72+ "string" ,
73+ "number" ,
74+ "true" ,
75+ "false" ,
76+ "null" ,
77+ }
6378
6479
6580def is_text_file (filepath : Path , sample_size : int = 2048 ) -> bool :
@@ -77,7 +92,7 @@ def is_text_file(filepath: Path, sample_size: int = 2048) -> bool:
7792 return False
7893
7994
80- # @Tree-sitter parser initialization for multiple languages, IMPL_LANG_1, impl, [FE_C_SUPPORT, FE_CPP, FE_PY, FE_YAML, FE_RUST]
95+ # @Tree-sitter parser initialization for multiple languages, IMPL_LANG_1, impl, [FE_C_SUPPORT, FE_CPP, FE_PY, FE_YAML, FE_RUST, FE_JSONC ]
8196def init_tree_sitter (comment_type : CommentType ) -> tuple [Parser , Query ]:
8297 if comment_type == CommentType .cpp :
8398 import tree_sitter_cpp # noqa: PLC0415
@@ -104,6 +119,11 @@ def init_tree_sitter(comment_type: CommentType) -> tuple[Parser, Query]:
104119
105120 parsed_language = Language (tree_sitter_rust .language ())
106121 query = Query (parsed_language , RUST_QUERY )
122+ elif comment_type == CommentType .jsonc :
123+ import tree_sitter_json # noqa: PLC0415
124+
125+ parsed_language = Language (tree_sitter_json .language ())
126+ query = Query (parsed_language , JSONC_QUERY )
107127 else :
108128 raise ValueError (f"Unsupported comment style: { comment_type } " )
109129 parser = Parser (parsed_language )
@@ -203,8 +223,11 @@ def find_yaml_next_structure(node: TreeSitterNode) -> TreeSitterNode | None:
203223 return None
204224
205225
206- def find_yaml_prev_sibling_on_same_row (node : TreeSitterNode ) -> TreeSitterNode | None :
207- """Find a previous named sibling that is on the same row as the comment."""
226+ def find_prev_sibling_on_same_row (node : TreeSitterNode ) -> TreeSitterNode | None :
227+ """Find a previous named sibling that is on the same row as the comment.
228+
229+ Grammar-agnostic: used to detect inline comments in both YAML and JSONC.
230+ """
208231 comment_row = node .start_point .row
209232 current = node .prev_named_sibling
210233
@@ -225,7 +248,7 @@ def find_yaml_prev_sibling_on_same_row(node: TreeSitterNode) -> TreeSitterNode |
225248def find_yaml_associated_structure (node : TreeSitterNode ) -> TreeSitterNode | None :
226249 """Find the YAML structure (key-value pair, list item, etc.) associated with a comment."""
227250 # First, check if this is an inline comment by looking for a previous sibling on the same row
228- prev_sibling_same_row = find_yaml_prev_sibling_on_same_row (node )
251+ prev_sibling_same_row = find_prev_sibling_on_same_row (node )
229252 if prev_sibling_same_row :
230253 return prev_sibling_same_row
231254
@@ -244,6 +267,35 @@ def find_yaml_associated_structure(node: TreeSitterNode) -> TreeSitterNode | Non
244267 return None
245268
246269
270+ def find_jsonc_associated_structure (node : TreeSitterNode ) -> TreeSitterNode | None :
271+ """Find the JSON structure (key/value pair, value, list item) for a comment.
272+
273+ JSON is data rather than code, so association follows the same intent as YAML:
274+ an inline comment belongs to the value on its row, a leading comment belongs to
275+ the following structure, otherwise it belongs to the enclosing structure.
276+ """
277+ # Inline comment: a value/pair on the same row, before the comment
278+ prev_sibling_same_row = find_prev_sibling_on_same_row (node )
279+ if prev_sibling_same_row :
280+ return prev_sibling_same_row
281+
282+ # Leading comment: the next structure following the comment
283+ current = node .next_named_sibling
284+ while current :
285+ if current .type in JSON_STRUCTURE_TYPES :
286+ return current
287+ current = current .next_named_sibling
288+
289+ # Otherwise: the enclosing structure
290+ parent = node .parent
291+ while parent :
292+ if parent .type in {"pair" , "object" , "array" }:
293+ return parent
294+ parent = parent .parent
295+
296+ return None
297+
298+
247299def find_associated_scope (
248300 node : TreeSitterNode , comment_type : CommentType = CommentType .cpp
249301) -> TreeSitterNode | None :
@@ -252,6 +304,10 @@ def find_associated_scope(
252304 # YAML uses different structure association logic
253305 return find_yaml_associated_structure (node )
254306
307+ if comment_type == CommentType .jsonc :
308+ # JSONC uses data-aware structure association logic
309+ return find_jsonc_associated_structure (node )
310+
255311 if node .type == CommentCategory .docstring :
256312 # Only for python's docstring
257313 return find_enclosing_scope (node , comment_type )
0 commit comments