Skip to content

Commit f94d998

Browse files
committed
add preserve case recipe
1 parent dcbb9b1 commit f94d998

File tree

4 files changed

+147
-7
lines changed

4 files changed

+147
-7
lines changed
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
Controls how variable keys defined using dot notation are handled:
22

3-
When preserveCase="false" (default): All struct keys defined with dot notation are converted to uppercase.
4-
Example: sct.dotNotation becomes key "DOTNOTATION" while sct["bracketNotation"] remains "bracketNotation"
5-
6-
When preserveCase="true": Struct keys defined with dot notation maintain their original case.
7-
Example: sct.dotNotation remains key "dotNotation" and sct["bracketNotation"] remains "bracketNotation"
8-
9-
This setting affects all dot notation usage throughout the template.
3+
When `preserveCase="false"` (default): All struct keys defined with dot notation are converted to uppercase.
4+
5+
Example: `sct.dotNotation` becomes key `"DOTNOTATION" while sct["bracketNotation"]` remains `"bracketNotation"`
6+
7+
When `preserveCase="true"`: Struct keys defined with dot notation maintain their original case.
8+
9+
Example: `sct.dotNotation` remains key `"dotNotation"` and `sct["bracketNotation"]` remains `"bracketNotation"`
10+
11+
This setting affects all dot notation usage throughout the template.
12+
13+
This can be configured server wide
14+
15+
- Lucee Admin, under Settings, Language/Compiler, Key Case
16+
- Using `.CFConfig.json` using `"dotNotationUpperCase": boolean`

docs/03.reference/02.tags/processingdirective/tag.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ id: tag-processingdirective
44
related:
55
- tag-output
66
- tag-setting
7+
- language-syntax-differences
78
categories:
89
- debugging
910
- server
11+
- struct
1012
---
1113

1214
Sets compiler directives that affect the entire template. Unlike most CFML tags, cfprocessingdirective is processed at compile time and must be placed at the root level of your template.

docs/05.categories/262.scopes/category.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
title: 'Scopes'
33
id: category-scopes
44
related:
5+
- category-struct
56
---
67

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<!--
2+
{
3+
"title": "Structures and variables, preserving the original case",
4+
"id": "struct-preserve-key-case",
5+
"categories": ["struct", "best-practices", "components"],
6+
"description": "How to configure preserve case for struct keys",
7+
"keywords": [
8+
"struct",
9+
"dotNotationUpperCase",
10+
"preserve case"
11+
],
12+
"related": [
13+
"tag-processingdirective",
14+
"tag-setting",
15+
"function-structnew",
16+
"scopes"
17+
]
18+
}
19+
-->
20+
21+
# Preserving Key Case in CFML Structs / Variables
22+
23+
## The Problem
24+
25+
You're building a REST API and returning a struct as JSON. Your code looks clean:
26+
27+
```lucee
28+
sct = {};
29+
sct.firstName = "James";
30+
sct.lastName = "Kirk";
31+
serializeJSON( sct );
32+
```
33+
34+
But the JSON output has uppercase keys:
35+
36+
```json
37+
{"FIRSTNAME":"James","LASTNAME":"Kirk"}
38+
```
39+
40+
Your JavaScript frontend expects `firstName`, not `FIRSTNAME`. What's going on?
41+
42+
## Why This Happens
43+
44+
In CFML, variable names are **case-insensitive**. To achieve this, Lucee converts all keys defined with dot notation to uppercase at compile time. This is the traditional CFML behaviour.
45+
46+
```lucee
47+
sct = {};
48+
sct.firstName = "James"; // Would be stored as "FIRSTNAME"
49+
sct["firstName"] = "Jamez"; // Would be still stored as "FIRSTNAME" (see note)
50+
sct["lastName"] = "Kirk"; // Would be stored as "lastName" (bracket notation preserves case)
51+
```
52+
53+
Note: in the above example, once a key is created, updating it will not change the key case, so `sct["firstName"]` does not change the original key case.
54+
55+
All variables in Lucee are stored in structs under the hood - `variables`, `local`, `arguments`, `url`, `form` - they all follow the same rules.
56+
57+
## Solutions
58+
59+
### Use Bracket Notation
60+
61+
Bracket notation **always** preserves case:
62+
63+
```lucee
64+
sct = {};
65+
sct["firstName"] = "James";
66+
sct["lastName"] = "Kirk";
67+
```
68+
69+
### Server-Wide Configuration
70+
71+
If you want dot notation to preserve case everywhere, Lucee has a compiler setting called `dotNotationUpperCase`.
72+
73+
- **`true`** (default): Convert dot notation keys to uppercase (CFML standard)
74+
- **`false`**: Preserve the original case
75+
76+
#### Configuring via Lucee Admin
77+
78+
1. Open the Lucee Server or Web Admin
79+
2. Navigate to **Settings → Language/Compiler**
80+
3. Under **Key Case**, select "Preserve case"
81+
82+
#### Configuring via .CFConfig.json
83+
84+
```json
85+
{
86+
"dotNotationUpperCase": false
87+
}
88+
```
89+
90+
#### Configuring via Environment Variable
91+
92+
```bash
93+
LUCEE_PRESERVE_CASE=true
94+
```
95+
96+
Or as a system property:
97+
98+
```bash
99+
-Dlucee.preserve.case=true
100+
```
101+
102+
Note: The environment variable uses **preserve case** logic (inverse of `dotNotationUpperCase`), so `true` means preserve case.
103+
104+
## Per-Template Override
105+
106+
You can override the server setting for a specific template using [[tag-processingdirective]]
107+
108+
```lucee
109+
<cfprocessingdirective preserveCase="true">
110+
111+
<cfscript>
112+
sct = {};
113+
sct.firstName = "James"; // Preserved as "firstName" in this template
114+
</cfscript>
115+
```
116+
117+
## Checking the Current Setting
118+
119+
You can check what setting is active:
120+
121+
```lucee
122+
settings = getApplicationSettings();
123+
writeOutput( settings.dotNotationUpperCase ); // true or false
124+
```
125+
126+
## Things to Consider
127+
128+
When set via the Lucee Admin / `CFConfig.json`, keep in mind this is server wide configuation.
129+
130+
If you're working with legacy code that assumes uppercase keys, switching to preserve case could break things. Test thoroughly.

0 commit comments

Comments
 (0)