Repository navigation
fix(twig): count {# #} comments - #798
Conversation
Twig writes a comment as {# ... #}, and its lexer drops everything from
the {# up to the first #} after it, newlines included, without nesting.
The Twig Template entry in languages.json declared no comment at all, so
every line of a Twig comment counted as code, including the docblock
that opens most Drupal templates, and a tag commented out inside one
still added to complexity.
Declare {# #} as Twig's block comment, the same pair the Jinja entry
uses, and update processor/constants.go to match. The #} closer also
ends the -#} and ~#} whitespace control forms. LANGUAGES.md lists names
and extensions only, so it does not change.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
There was a problem hiding this comment.
You mentioned you couldn't run Go locally, so I ran it on this branch (69b8aea, Go 1.27.3):
go test ./...passes (root,cmd/badges,processor).go generate ./...leaves the tree clean, so theprocessor/constants.gohunk matches whatscripts/include.gogenerates fromlanguages.json.- With the parent commit's
constants.goswapped back in, the new tests fail exactly as your port predicted:Expected 4 code got 7,Expected 3 code got 12,Expected 1 code got 6(andcomplexity 0 got 1).TestCountStatsTwigCommentNextToMarkupIsCodepasses both ways, as you said.
On the limitation you called out (no quotes for Twig, so a {# inside a string opens a comment), here is a concrete example of what it costs:
{{ "{#" ~ id }}
<p>{{ a }}</p>
{% if b %}x{% endif %}
{# c #}Twig Template 1 4 0 3 1 0
Line 1 stays code, but lines 2 and 3 are counted as comment, and the {% if complexity is lost. Going by how Twig's own lexer reads the file, it should be 3 code, 1 comment, complexity 1. I agree with leaving quotes empty: adding "/' would make every apostrophe in the HTML text open a string, which is far worse. Two optional suggestions: keep this case as a short known-limitation test, so a later change to quote handling shows up as a diff, and add a one-line note in the PR or commit message saying Twig strings are deliberately not modelled.
|
Cheers. |
What's broken
Twig writes a comment as
{# ... #}(Templates, Comments), and the defaulttag_commentin Twig'ssrc/Lexer.phpis['{#', '#}']. A comment runs from{#to the first#}after it, across lines, and comments do not nest.The
Twig Templateentry inlanguages.json(line 8234) declares no comment at all:so scc never reports a comment in a Twig file. Every line of a
{# #}comment counts as code, including the docblock that opens 495 of Drupal core's 707 templates, and a tag commented out inside{# #}still adds to complexity.Repro
Across the 707
.twigfiles in Drupal core (cf863a1), 10,231 of the 22,518 lines move from code to comments, and code drops from 22,061 to 11,836.The fix
"multi_line": [["{#", "#}"]]for Twig Template, the pair theJinjaentry already uses, plus the matching entry inprocessor/constants.go. The#}closer also ends the-#}and~#}whitespace control forms, and leavingnestedmultilineoff matches Twig.LANGUAGES.mdlists names and extensions only, so it does not change.One limit: scc can't tell
{% verbatim %}text or a string literal inside a tag apart, so a{#in one of those (a Handlebars{{#each}}kept verbatim, say) opens a comment. Everywhere else Twig's own lexer reads{#as a comment opener too, so the two agree.Verification
processor/workers_twig_comment_test.goadds fourCountStatstests: comments on their own line (including the{#- -#}and{#~ ~#}forms), a multi-line docblock, a commented-out{% if %}that no longer adds complexity, and a guard where a comment shares a line with markup and the line stays code. The guard passes on master too.There is no Go toolchain on the machine I made this on, so I haven't run
go testorgo generatemyself. CI will. I worked out the expected counts with a line-for-line Python port ofcountLoopGenericand the state functions it calls. That port reproduces the counts asserted by 69 existingCountStatstests inprocessor/. By the port, the three behaviour tests fail on master (Expected 4 code got 7,Expected 3 code got 12,Expected 1 code got 6) and all four pass on this branch. The Drupal figures above come from the same port. Theprocessor/constants.gohunk is byte for byte what a Python port ofscripts/include.goproduces, and that port reproduces master'sconstants.goexactly.I explicitly licence this contribution under the MIT licence.
🤖 Generated with Claude Code