Template operators differ from JavaScript in compatibility mode
What you'll see
JavaScript that is correct in an API file behaves differently in a .hash page:
#{
let h = 5381;
for (let i = 0; i < text.length; i++) {
h ^= text.charCodeAt(i); // does nothing in a .hash page
}
}#No error, no warning — h just stays 5381. The same code in #/API/ changes h as expected.
Related symptoms in the same family:
let y = ~!x;fails to compile withparsing failed of operator '~!'.if (a ^!b)is read as "adoes not containb", not asa ^ (!b).
What's actually happening
.hash pages outside #/API/ run in compatibility mode: plain JavaScript plus Docly's older template syntax. That syntax includes text operators made of two characters:
| Operator | In compatibility mode | In plain JavaScript |
|---|---|---|
a ^= b | a contains b (case-sensitive) | XOR assignment |
a ~= b | a contains b (not case-sensitive) | syntax error |
a ^! b | a does not contain b (case-sensitive) | a ^ (!b) |
a ~! b | a does not contain b (not case-sensitive) | syntax error |
a ^ b, ~a | XOR, NOT | XOR, NOT |
The pair wins whenever the two characters touch. h ^= x; on its own line is therefore a comparison: it evaluates to true or false, nobody uses the value, and h is never assigned. That is why there is no error.
A single ^ or ~ has no template meaning, so it is plain bitwise XOR and NOT in both modes. (Older Docly versions rejected a bare ^ or ~ in a .hash page with Unknown token '^' in expression. If you still see that error, write the XOR as ((a | b) - (a & b)), or move the code to an API file.)
What to do
Write the assignment out. It works the same in both modes:
h = h ^ text.charCodeAt(i); // not: h ^= ...
h = ((h * 33) ^ text.charCodeAt(i)) >>> 0; // a typical string hashSeparate characters you mean separately: a ^ !b with a space, and ~(!x) instead of ~!x.
On a new site, avoid the pitfall entirely by starting in the strictest mode — see Start new sites in strict JavaScript mode.
Or turn compatibility mode off, and the page is plain JavaScript, exactly like an API file:
- For the site's
.hashpages:"hashjs": { "compatibilityMode": false }in#/site.json. See Site.json config file. - For a template stored in a schema: tick Modern syntax in that template's settings in the schema editor.
Turning it off also removes the bracket conditions (#[Field]#…#[/Field]#), the other text operators ($= and friends), case-insensitive function names and .Length/.Count. Check that the pages compile before switching a live site.
When a .hash page computes something different from the same code in an API file, suspect a two-character operator first. Test the expression on its own in a scratch page — see Use a scratch hash file to test Docly functions.