@cfmleditor/tree-sitter-cfml
v0.26.2
Published
CFML grammar for tree-sitter
Maintainers
Readme
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
npm install @cfmleditor/tree-sitter-cfmlconst { cfml, cfhtml, cfscript, cfquery } = require('@cfmleditor/tree-sitter-cfml');
const Parser = require('tree-sitter');
const parser = new Parser();
parser.setLanguage(cfhtml.language);
const tree = parser.parse('<cfif condition>#value#</cfif>');
console.log(tree.rootNode.toString());Rust
Add to your Cargo.toml:
[dependencies]
tree-sitter = "0.25"
tree-sitter-cfml = "0.26"use tree_sitter_cfml::{LANGUAGE_CFML, LANGUAGE_CFHTML, LANGUAGE_CFSCRIPT, LANGUAGE_CFQUERY};
// cfml for .cfc component files
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE_CFML.into())
.expect("Error loading CFML grammar");
// cfhtml for .cfm template files
parser.set_language(&LANGUAGE_CFHTML.into())
.expect("Error loading CFHTML grammar");
// cfscript for .cfs pure script files
parser.set_language(&LANGUAGE_CFSCRIPT.into())
.expect("Error loading CFSCRIPT grammar");Python
pip install tree-sitter-cfmlimport tree_sitter_cfml as ts_cfml
from tree_sitter import Language, Parser
# cfhtml for .cfm template files
parser = Parser(Language(ts_cfml.language_cfhtml()))
tree = parser.parse(b'<cfif x GT 0>#x#</cfif>')
# cfml for .cfc component files
parser = Parser(Language(ts_cfml.language_cfml()))
# cfscript for .cfs pure script files
parser = Parser(Language(ts_cfml.language_cfscript()))
# cfquery SQL dialect (embedded)
parser = Parser(Language(ts_cfml.language_cfquery()))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:
cd cfml && make
cd cfhtml && make
cd cfscript && makeOr build all three plus the Node.js bindings:
npm run buildNote 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:
cd cfml && tree-sitter generate
cd cfhtml && tree-sitter generate
cd cfscript && tree-sitter generateTesting
# Test a single grammar
cd cfml && tree-sitter test
# Test all grammars
npm testParsing a file
cd cfml && tree-sitter parse path/to/file.cfcPlayground
npm run playgroundGrammar 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 navigationQueries
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

