Skip to content

feat(lang): CFML tag-dialect .cfc routing + embedded <cfscript> defs - #1412

Open
allanoepping wants to merge 1 commit into
DeusData:mainfrom
allanoepping:feat/cfml-tag-dialect-and-embedded-cfscript
Open

feat(lang): CFML tag-dialect .cfc routing + embedded <cfscript> defs#1412
allanoepping wants to merge 1 commit into
DeusData:mainfrom
allanoepping:feat/cfml-tag-dialect-and-embedded-cfscript

Conversation

@allanoepping

Copy link
Copy Markdown

Summary

Two extraction fixes for legacy tag-based CFML / ColdFusion. The vendored
cfmleditor/tree-sitter-cfml grammar is Lucee-tuned and script-first, so on
older codebases (predominantly <cfcomponent> tag components with <cfscript>
bodies) most functions were never extracted. Both fixes mirror existing
conventions in the codebase.

1. .cfc dialect disambiguation — cbm_disambiguate_cfc()

The extension table maps .cfc → cfscript unconditionally, but a .cfc may be
script-dialect (component { … }) or tag-dialect (<cfcomponent> … </cfcomponent>).
New content-sniff (same shape as cbm_disambiguate_cls/inc):

  • <cfcomponent> or a bare top-level <cffunction>CBM_LANG_CFML (tag grammar)
  • a leading <cfscript>-wrapped component {}, or a plain script component → CBM_LANG_CFSCRIPT
  • leading <!--- ---> comments are skipped before deciding

2. Embedded <cfscript> definitions — cbm_extract_embedded_defs()

The HTML-derived cfml grammar keeps <cfscript> bodies as an opaque
cf_script_content token, so script functions inside tag components produced no
function_declaration nodes. This re-parses each cf_script_tag → cf_script_content
slice with the cfscript grammar (reusing the embedded_imports machinery) and
walks it for definitions via a new cbm_extract_definitions_body() that skips the
Module node. Block-relative line numbers are shifted by the block's start row —
CBMDefinition carries only line positions, so a constant offset is a complete
remap. Definitions only (calls/usages would need byte remapping), so existing
edges cannot be corrupted. Bonus: functions are recovered even when a <cfsetting>
void-tag ERROR cascade damages the surrounding tree.

Adds an embedded_defs field to CBMLangSpec, wired only to CBM_LANG_CFML.

Tests

  • extract_cfml_embedded_cfscript_defs — script funcs inside <cfscript> in a tag
    component extract with correct (remapped) line numbers, alongside a <cffunction>.
  • 8 × lang_cfc_* — tag / script / <cfscript>-wrapped / bare <cffunction> /
    leading-comment / read-fail routing.

scripts/test.sh --suites "language extraction grammar_regression" → 497 passed, 0 failed.

Real-world impact

Indexing a ~700-file legacy CFML app (156/176 .cfc are tag-based):

  • parse timeouts 4 → 0
  • api.cfc 0 → 62 functions, api-a.cfc 0 → 48
  • +1,532 function nodes overall, with exact line numbers

Notes

Not addressed here: <cfsetting> (and other void CF tags) still emit tree-sitter
ERROR nodes in the cfml grammar — cosmetic now that functions are recovered, but
a genuine grammar issue that belongs in cfmleditor/tree-sitter-cfml (regenerating
parser.c from grammar.js).

@allanoepping
allanoepping requested a review from DeusData as a code owner August 2, 2026 06:31
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@allanoepping
allanoepping force-pushed the feat/cfml-tag-dialect-and-embedded-cfscript branch from 0ff692d to aeac05c Compare August 2, 2026 16:48
@allanoepping

allanoepping commented Aug 2, 2026

Copy link
Copy Markdown
Author

The Windows red check (test-windows … 2/2, plus the downstream ci-ok / shard-completeness aggregates) is unrelated to this change — it fails in the Step-0 static infrastructure contracts, not in any test suite or in code this PR touches (CFML .cfc disambiguation + embedded <cfscript> definition extraction, all in the C extraction path).

Two Windows-runner environmental failures surface there:

  • Step 0a — path-safety.sh: ERROR: repository build/ ancestor must be absent or a real directory. build/ is gitignored, so a clean checkout has it absent; this fires only when the runner leaves build/ as a symlink/non-dir (a cache/filesystem artifact on the Windows VM).
  • Step 0i — parallel suite scheduler contract: a file-lock race during cleanup —
    rm: cannot remove '…/cbm-parallel-harness.…/logs/timeout_exit_race.log': Device or resource busy
    ValueError: invalid literal for int() with base 10: ''
    
    i.e. the scheduler's own timeout/hang fixtures (hang_after_summary, stubborn_tree, timeout_exit_race) left a handle open so the rm failed and empty output tripped an int('') parse.

Everything relevant is green, including the full suite under clang-TSAN on Linux + macOS (which exercises the new lang_cfc_* and extract_cfml_embedded_cfscript_defs tests): DCO, lint, all test-unix gcc shards, all test-tsan (ubuntu/arm/macOS clang), test-unix (macOS), and test-windows-guards. A re-run of the Windows shard should clear it.

@DeusData DeusData added bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. labels Aug 3, 2026
@DeusData DeusData added this to the 0.9.1-rc milestone Aug 3, 2026
@DeusData

DeusData commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Thank you for the CFML contribution and for covering both tag-dialect routing and embedded <cfscript> definitions. This is now triaged as a high-priority parsing fix in 0.9.1-rc because the existing route can silently produce an incomplete graph. This is an intake acknowledgement rather than a code review. Our community review queue is currently full, so it may take us a little time to validate the grammar surface, fixtures, and cross-language impact, but the PR is in the correct queue.

Two extraction fixes for legacy tag-based CFML/ColdFusion, where the
vendored cfmleditor grammar (Lucee-tuned, script-first) leaves most
real-world components unextracted.

1. .cfc dialect disambiguation (cbm_disambiguate_cfc)
   The extension table maps .cfc -> cfscript unconditionally, but legacy
   codebases are predominantly tag-based (<cfcomponent>). Content-sniff the
   file head, mirroring cbm_disambiguate_cls/inc: <cfcomponent>/<cffunction>
   route to the cfml tag grammar; a leading <cfscript>-wrapped "component {}"
   or a plain script component route to cfscript; leading <!--- ---> comments
   are skipped.

2. Embedded <cfscript> definition extraction (cbm_extract_embedded_defs)
   The HTML-derived cfml grammar keeps <cfscript> bodies as opaque
   cf_script_content, so script functions inside tag components were never
   extracted. Re-parse cf_script_tag -> cf_script_content slices with the
   cfscript grammar (reusing the embedded-imports machinery) and walk them
   for definitions via a new cbm_extract_definitions_body() that skips the
   Module node. Block-relative line numbers are shifted by the block's start
   row; CBMDefinition carries only line positions, so a constant offset is a
   complete remap. Definitions only (calls/usages would need byte remapping),
   so existing edges cannot be corrupted. As a bonus, functions are recovered
   even when a <cfsetting> void-tag ERROR cascade damages the surrounding tree.

The opt-in is an extract_definitions flag on CBMEmbeddedLangSpec (carried by
CFML's embedded_imports entry), not a new CBMLangSpec field -- the latter
would trip -Wmissing-field-initializers across every language row under
clang -Werror.

Tests: extract_cfml_embedded_cfscript_defs (extraction + line remap) and
eight lang_cfc_* disambiguation cases. Verified on a ~700-file legacy CFML
codebase: parse timeouts 4->0, api.cfc 0->62 functions, +1,532 function
nodes overall, with exact line numbers.

Signed-off-by: Allan Oepping <allan@intellipay.com>
@allanoepping
allanoepping force-pushed the feat/cfml-tag-dialect-and-embedded-cfscript branch from aeac05c to 88aab7a Compare August 4, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants