tree-sitter-cfml
Tree-sitter grammars for ColdFusion Markup Language (CFML).
Three grammars are provided to cover the different ways CFML is written, plus an embedded SQL dialect for cfquery:
| Grammar | Scope | File types | Description |
|---|---|---|---|
cfml |
source.cfml |
.cfc |
ColdFusion components — CFScript inside a component {} block or tag-based component files |
cfhtml |
source.cfhtml |
.cfm |
CFML template files — HTML with embedded CF tags and hash expressions |
cfscript |
source.cfscript |
.cfs |
Pure CFScript files |
cfquery |
source.cfquery |
(embedded) | SQL dialect used inside <cfquery> bodies (and compatible with QueryExecute-style usage) with CF-style #hash# interpolation and CF tags in the body |
Playground
Try the grammars in the browser: cfmleditor.github.io/tree-sitter-cfml
Installation
Node.js
const = require;
const Parser = require;
const parser = ;
parser.;
const tree = parser.;
console.log;
Rust
Add to your Cargo.toml:
[]
= "0.25"
= "0.26"
use ;
// cfml for .cfc component files
let mut parser = new;
parser.set_language
.expect;
// cfhtml for .cfm template files
parser.set_language
.expect;
// cfscript for .cfs pure script files
parser.set_language
.expect;
Python
# cfhtml for .cfm template files
=
=
# cfml for .cfc component files
=
# cfscript for .cfs pure script files
=
# cfquery SQL dialect (embedded)
=
Go
import (
tree_sitter_cfml "github.com/cfmleditor/tree-sitter-cfml/bindings/go"
sitter "github.com/tree-sitter/go-tree-sitter"
)
// cfml for .cfc component files
parser := sitter.NewParser()
parser.SetLanguage(sitter.NewLanguage(tree_sitter_cfml.LanguageCfml()))
// cfhtml for .cfm template files
parser.SetLanguage(sitter.NewLanguage(tree_sitter_cfml.LanguageCfhtml()))
// cfscript for .cfs pure script files
parser.SetLanguage(sitter.NewLanguage(tree_sitter_cfml.LanguageCfscript()))
// cfquery SQL dialect (embedded)
parser.SetLanguage(sitter.NewLanguage(tree_sitter_cfml.LanguageCfquery()))
Development
Requirements
- tree-sitter CLI (
npm install -g tree-sitter-cli) - A C compiler
Building
Each grammar is built independently from its subdirectory:
&&
&&
&&
Or build all three plus the Node.js bindings:
Note on build warnings
When running npm run build, you may see tree-sitter warnings about “unnecessary conflicts” such as binary_expression, call_expression, switch_case, or assignment_expression versus _property_name, and hash-related conflicts for the cfquery dialect.
These conflicts are intentionally declared in common/define-grammar.js to resolve real ambiguities in CFML/CFHTML/cfquery syntax; attempts to remove them cause tree-sitter generate to fail with unresolved conflicts. It is safe to ignore these warnings as long as the build and tests succeed.
Generating the parser
After editing common/define-grammar.js:
&&
&&
&&
Testing
# Test a single grammar
&&
# Test all grammars
Parsing a file
&&
Playground
Grammar structure
All four grammars share a common base defined in common/define-grammar.js, with an external scanner in common/scanner.h that handles context-sensitive tokenisation (implicit end tags, CF tag names, hash expressions, raw text, etc.).
common/
define-grammar.js # shared grammar rules for all three dialects
scanner.h # external scanner (C)
tag.h # HTML/CF tag type definitions
cfml/ # .cfc grammar
cfhtml/ # .cfm grammar
cfscript/ # .cfs grammar
cfquery/ # cfquery SQL dialect (embedded)
grammar.js # entry point (calls defineGrammar with dialect name)
src/ # generated parser (do not edit)
queries/
highlights.scm # syntax highlighting
indents.scm # indentation
injections.scm # language injections
tags.scm # symbol navigation
Queries
Each grammar ships with query files for editor integration:
highlights.scm— syntax highlighting capturesindents.scm— indentation rulesinjections.scm— embedded language injections (e.g. SQL inside<cfquery>)tags.scm— function/method definitions and call references for go-to-definition and symbol search
License
MIT
