@@ -80,3 +80,66 @@ def test_the_citation_is_gone_from_the_source_not_just_one_path():
8080 assert "may be partially extracted: {_shown}{_more} (#2551)" not in text
8181 assert "no symbols extracted" in text
8282 assert "symbol(s) extracted" in text
83+
84+
85+ # ── #3946: a clean-parse file that yields nothing but its own file node ─────
86+
87+ def _data_only_fixture (tmp_path ):
88+ """A plain data literal with no functions, classes or imports — the AST
89+ extractor has nothing to model, but the file parses with zero errors, so
90+ the syntax-error warning above must stay silent for it."""
91+ f = tmp_path / "data.js"
92+ f .write_text ("module.exports = [{a: 1}, {b: 2}];\n " , encoding = "utf-8" )
93+ return f
94+
95+
96+ def test_symbolless_warning_names_the_file (tmp_path , capsys ):
97+ err = _run (tmp_path , [_data_only_fixture (tmp_path )], capsys )
98+ assert "yielded no symbols" in err , err
99+ assert "data.js" in err
100+ # neutral wording: a symbol-less file may be data OR source the extractor
101+ # models nothing for — do NOT assert it is "data rather than code".
102+ assert "may be data rather than code" not in err
103+
104+
105+ def test_symbolless_warning_is_silent_for_an_empty_init (tmp_path , capsys ):
106+ """An empty __init__.py is symbol-less *code*, ubiquitous in Python
107+ packages. It has nothing to model, so the warning must stay silent rather
108+ than fire on essentially every package scan."""
109+ pkg = tmp_path / "pkg"
110+ pkg .mkdir ()
111+ (pkg / "__init__.py" ).write_text ("" , encoding = "utf-8" )
112+ err = _run (tmp_path , [pkg / "__init__.py" ], capsys )
113+ assert "yielded no symbols" not in err
114+
115+
116+ def test_symbolless_warning_is_silent_for_a_whitespace_only_file (tmp_path , capsys ):
117+ f = tmp_path / "blank.py"
118+ f .write_text ("\n \n \t \n " , encoding = "utf-8" )
119+ err = _run (tmp_path , [f ], capsys )
120+ # whitespace-only: nothing to model, so the strip-empty guard keeps it quiet
121+ assert "yielded no symbols" not in err
122+
123+
124+ def test_symbolless_warning_does_not_fire_for_a_real_function (tmp_path , capsys ):
125+ f = tmp_path / "real.js"
126+ f .write_text ("function run() { return 1; }\n " , encoding = "utf-8" )
127+ err = _run (tmp_path , [f ], capsys )
128+ assert "yielded no symbols" not in err
129+
130+
131+ def test_symbolless_warning_does_not_overlap_the_syntax_error_warning (tmp_path , capsys ):
132+ """A file already explained by the partial-extraction warning (a genuine
133+ parse error) must not ALSO be counted as a clean-parse data file."""
134+ err = _run (tmp_path , [_partial_parse_fixture (tmp_path )], capsys )
135+ assert "yielded no symbols" not in err
136+
137+
138+ def test_symbolless_warning_counts_total_size (tmp_path , capsys ):
139+ a = tmp_path / "a.js"
140+ a .write_text ("module.exports = [1, 2, 3];\n " , encoding = "utf-8" )
141+ b = tmp_path / "b.js"
142+ b .write_text ("export default [4, 5, 6];\n " , encoding = "utf-8" )
143+ err = _run (tmp_path , [a , b ], capsys )
144+ assert "2 code file(s) yielded no symbols" in err
145+ assert "a.js" in err and "b.js" in err
0 commit comments