# Reference: languages coloured > Neutral description of which files Turbo JS colours, how it decides, and what each scanner recognises. ## Recognition A file's **extension** decides whenever it is one of these: | Extension | Language | | --- | --- | | `.js`, `.mjs`, `.cjs` | JavaScript | | `.json`, `.jsonc` | JSON | | `.toml` | TOML | | `.yaml`, `.yml` | YAML | | `.md`, `.markdown` | Markdown | | `.html`, `.htm` | HTML | | `.xml`, `.xsd`, `.xsl`, `.xslt`, `.svg`, `.plist`, `.csproj`, `.pom` | XML | | `.sh`, `.bash`, `.zsh` | Shell | | `.dockerfile`, `.containerfile` | Dockerfile | Extensions are matched case-insensitively, and only the last one counts: `notes.js.md` is Markdown, `main.js.backup` is not JavaScript, and `main.test.js` is JavaScript. A file whose extension decides nothing is looked up by **name** next. Only files that carry no useful extension need this: | Name | Language | | --- | --- | | `Dockerfile`, `Containerfile` | Dockerfile | A name matches on the whole of it or on the part before the first dot, ignoring case — so `Dockerfile`, `dockerfile` and `Dockerfile.dev` are all recognised, while `Dockerfile.md` is Markdown, because the extension is consulted first. A file that neither table claims is read by its **first line**. A shebang naming `node` makes it JavaScript: a command-line tool written in JavaScript is a file with no extension whose first line is `#!/usr/bin/env node`, and Node strips that line before parsing. A shebang naming a shell — `sh`, `bash`, `zsh`, `dash` or `ksh` — makes it a shell script. The interpreter is recognised as a path element or as the argument to `env`. | First line | Result | | --- | --- | | `#!/usr/bin/env node` | JavaScript | | `#!/usr/local/bin/node` | JavaScript | | `#!/usr/bin/env -S node --no-warnings` | JavaScript | | `#!/bin/sh` | Shell | | `#!/usr/bin/env bash` | Shell | | `#!/usr/bin/env python3` | Not coloured | | Anything not starting `#!` | Not coloured | The order is fixed — extension, then name, then first line — and the first to decide wins. Everything else is shown in plain text. That is not an error — opening a PNG in the editor is not a mistake, it is just not coloured. In particular **TypeScript (`.ts`, `.tsx`), JSX (`.jsx`) and CSS are not coloured**: the language server serves `.ts` files all the same, but the scanner here is for JavaScript. ## Classes Every scanner produces the same vocabulary of classes, and each maps to one theme key. | Class | Theme key | Produced by | | --- | --- | --- | | `identifier` | `syntax.identifier` | JavaScript, JSON (a bare word, which is not JSON), TOML, shell, YAML, Dockerfile | | `keyword` | `syntax.keyword` | JavaScript, shell, HTML (doctype), XML, Dockerfile | | `type` | `syntax.type` | JavaScript (class names and capitalised names), TOML (table headers), YAML (tags) | | `builtin` | `syntax.builtin` | JavaScript (the standard library's and Node's globals), shell (builtins and expansions), YAML (anchors and aliases), Dockerfile (variables) | | `constant` | `syntax.constant` | JavaScript, JSON, TOML, shell, YAML, HTML and XML (entities) | | `function` | `syntax.function` | JavaScript, shell (the command) | | `string` | `syntax.string` | all | | `char` | `syntax.char` | JavaScript (regular-expression literals) | | `number` | `syntax.number` | JavaScript, JSON, TOML, shell, YAML, Dockerfile | | `comment` | `syntax.comment` | JavaScript, JSON, TOML, shell, HTML, YAML, XML, Dockerfile | | `operator` | `syntax.operator` | JavaScript, TOML, shell, HTML, YAML (block scalar headers), XML, Dockerfile | | `punctuation` | `syntax.punctuation` | JavaScript, JSON, TOML, shell, Markdown, YAML, Dockerfile | | `heading` | `syntax.heading` | Markdown | | `tag` | `syntax.tag` | HTML, XML | | `attribute` | `syntax.attribute` | JSON (keys), JavaScript (decorators), HTML, XML, Dockerfile (flags) | | `emphasis` | `syntax.emphasis` | Markdown | | `link` | `syntax.link` | Markdown | JavaScript produces no `heading`, `tag`, `emphasis` or `link` span. In `turbo-classic`, `syntax.number` and `syntax.constant` are both magenta and `syntax.char` is the green of `syntax.string`, so `42` and `true` share a colour there and so do `/re/` and `"re"`; other themes separate them. See [how to write your own theme](../how-to/write-a-theme.md) if you want to change it. ## JavaScript Hand-written, in `internal/jslang`, and registered under the same name as the scanner turbo-core ships for JavaScript, which it replaces. What it adds over the library's: regular-expression literals, the hashbang line, Node's globals, the name after `function` and `class`, private names, decorators, and a leading capital read as a class name. **Two constructs cross a line break**, and are carried to the next line: a `/* … */` block comment to its closing `*/`, and a `` `…` `` template literal to its closing backtick. Neither nests. An ordinary `'…'` or `"…"` string does **not** cross a line: an unterminated one is coloured to the end of its line, and the next line is code again. | Recognised | As | | --- | --- | | `as`, `async`, `await`, `break`, `case`, `catch`, `class`, `const`, `continue`, `debugger`, `default`, `delete`, `do`, `else`, `export`, `extends`, `finally`, `for`, `from`, `function`, `get`, `if`, `import`, `in`, `instanceof`, `let`, `new`, `of`, `return`, `set`, `static`, `super`, `switch`, `throw`, `try`, `typeof`, `var`, `void`, `while`, `with`, `yield`, and the reserved `enum`, `implements`, `interface`, `package`, `private`, `protected`, `public` | keyword | | `true`, `false`, `null`, `undefined`, `NaN`, `Infinity`, `this` | constant | | the standard library's globals — `Array`, `Object`, `Promise`, `Math`, `JSON`, `Map`, `Set`, `Symbol`, `BigInt`, `Error`, `TypeError`, `parseInt`, `setTimeout`, `structuredClone`, `fetch`, `URL`, … | builtin | | Node's globals — `process`, `Buffer`, `console`, `require`, `module`, `exports`, `__dirname`, `__filename`, `setImmediate`, `performance`, `crypto` — and the browser's `document` and `window` | builtin | | the name after `function`, `function*` or `async function` — `parse` in `function parse(input) {}` | function | | the name after `class` — `widget` in `class widget extends Base {}` | type | | any other name starting with an ASCII capital — `Greeter`, `EventEmitter`, `MyError` — even before a `(` | type | | any other name immediately before `(` — `compute(3)`, `obj.method()`, `this.#reset()` | function | | any word after `.` or `?.`, whatever it is spelt like — `map.get(k)` a function, `options.default` a name, `user?.class` a name | property, never a keyword | | `get`, `set`, `static`, `of`, `from` and `as` before a `(` — `get(key)` | function | | `#count`, a private member, the `#` included | identifier, or function before `(` | | `@decorator`, `@observable.ref`, the dotted path included | attribute | | any other name: a Unicode letter, `_` or `$`, then letters, digits and the same — `x`, `$el`, `_`, `café`, `名前` | identifier | | `"…"`, `'…'` with backslash escapes, on one line | string | | `` `…` ``, `${…}` interpolations included, across lines | string | | `/…/gi`, a regular-expression literal, flags included, where the previous token allows one and a closing `/` exists on the line | char | | `42`, `1_000`, `0xFF`, `0o17`, `0b1010`, `1.5e-3`, `2E+10`, `.5`, `10n`, `0xFFn` | number | | `//` to the end of the line; `/* … */` and `/** … */` across lines | comment | | `#!` on the first line of the file, to its end | comment | | `...` | punctuation, as one span | | `?.` | operator, as one span | | runs of `+-*/%=<>!&\|^~?:` — including `=>`, `??`, `===`, `**`, `>>>=` | operator | | `()[]{},;` and a lone `.` | punctuation | **A slash divides after a value and opens a regular expression everywhere else.** After a name, a number, a string, a template, a regular expression, `)` or `]`, a `/` is division. After an operator, `(`, `[`, `{`, `}`, `,`, `;`, `:`, a keyword, or at the start of a line, it opens a regular expression — **provided a closing `/` exists on the same line**; otherwise it divides, whatever came before it. A regular expression cannot cross a line, so that bound keeps a wrong guess to one line. **A point joins a number only when a digit follows it**, so `1.toString()` is the number `1`, a dot and a method. **The sign after an `e` is part of the number**, except in a hexadecimal literal, where `0xE+1` is a sum. **A capitalised name is a class by convention, not by rule.** JavaScript lets you write `const Count = 1`, and it is coloured as a class all the same, as is `MAX_SIZE`. Classes and constructors are what people capitalise, and the colour follows the people. **Not recognised**, each for a stated reason: | Not recognised | Because | | --- | --- | | The code inside `${…}` in a template | Colouring it means the scanner reaching back into itself with a nesting depth to carry, for a construct that is usually one short expression; the whole literal is a string | | A backtick inside `${…}` | For the same reason: it ends the template early, and the code after it is coloured as code until the next backtick | | A regular expression with no closing slash on its line | It cannot be one — the language forbids a newline in the literal — so the slash divides | | JSX | `