Only cfscript's `include "x.cfm";`, written outside any function, linked
the including code to the template. CfmlExtractor never read
`<cfinclude template="...">`, which the grammar parses as a
cf_selfclose_tag whose name is only in the text after `<cf`, so the tag
form made nothing anywhere. cfscript's include hook read only the string
form, `cfinclude(template="x.cfm")` went through the call extractor as a
call to `cfinclude`, and the function-body walker never extracts import
statements, so an `include` in a function was dropped. Resolution went
through the generic pipeline: the file-name matcher links a relative path
like `../shared/helpers.cfm` only when no other file shares its name, and
past it the symbol strategies could take another template's import node
of the same path, or the including file itself.
Fix:
- `<cfinclude template="...">` is extracted like the script form: an
import node in the scope it sits in (function, component, or the
template's file) and an imports reference from that scope.
`cfinclude(...)` and `include template="...";` make the same import and
no call, and an `include` in a function body counts, from the function.
- A path built at runtime (`#dir#/x.cfm`) is no import, in every form.
- A CFML include of a template path resolves as CFML does: relative to the
including file's directory, or from the project root for a leading `/`
(less sure, 0.85), to the file at that path, ignoring case when one file
matches. A path that names no file there goes to the file-name matcher,
as before, but only ever to a file, and never to the including file.
Validation:
- New cfml-include.test.ts: the tag form at component level (same folder,
../, upper case, unquoted), in a function body inside <cfif>, in a
template and from the web root; the script forms; runtime-built paths,
cfinclude(template=variables.x) and <cfmodule> (no import); a relative
path with a namesake elsewhere; an unmatched path that another template
also includes, and a path whose only namesake is the includer. 5 of 7
fail on main, all 7 pass.
- A/B vs main 51c4124d (CFML has no kernel path) on FW/1, BlogCFC,
ColdBox, ContentBox, Preside, CFWheels and its vendor/wheels core as a
project of its own: 127 new imports edges and 152 import nodes (36
more resolved again to the same file, more surely); 9 import nodes of
runtime-built paths gone; 1 edge gone, CFWheels' starter-app
views/wheels/wheels.cfm including itself. No edge moved to another
target. Every CFML imports edge in the fix graphs (225) targets a file
named like the include path, and every relative path that stays inside
the project reaches exactly that file but one: Wheels' Public.cfc
including views/routetesterprocess.cfm, no file beside it, matched by
name to public/views/routetesterprocess.cfm as before. express and flask
controls byte-identical.
- Index time, median of 4 interleaved runs, CPU with workers, main vs
fix: Preside 52.6 / 50.8 s, Wheels core 28.2 / 29.5 s. Within noise.
Refs #2651 (part 1; part 2 is a feature request and stays open)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>