{"_id":"@codincod/codemirror-lang-fennel","name":"@codincod/codemirror-lang-fennel","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@codincod/codemirror-lang-fennel","version":"0.1.0","description":"Fennel language support for the CodeMirror code editor","keywords":["editor","code"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","type":"module","main":"dist/index.cjs","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"module":"dist/index.js","types":"dist/index.d.ts","sideEffects":false,"scripts":{"build":"rm -rf dist && lezer-generator src/fennel.grammar -o src/parser.js && cm-buildhelper src/fennel.ts","build-debug":"lezer-generator src/fennel.grammar --names -o src/parser.js && cm-buildhelper src/fennel.ts","prepare":"npm run build","test":"npm run build && node --test \"test/*.test.ts\"","corpus":"npm run build && node ../lezer-survey/src/cli.ts measure --group parent","fuzz":"npm run build && node ../lezer-survey/src/cli.ts fuzz","gaps":"npm run build && node ../lezer-survey/src/cli.ts gaps --group parent"},"dependencies":{"@codemirror/autocomplete":"^6.0.0","@codemirror/language":"^6.0.0","@lezer/highlight":"^1.0.0","@lezer/lr":"^1.0.0"},"devDependencies":{"@codemirror/buildhelper":"^1.0.2","@codemirror/state":"^6.7.1","@lezer/generator":"^1.7.0","typescript":"^5.6.0"},"homepage":"https://codincod.com/","repository":{"type":"git","url":"https://codeberg.org/reeven/codemirror-lang-fennel"},"_id":"@codincod/codemirror-lang-fennel@0.1.0","_nodeVersion":"25.0.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-J38Xu6kfoEeyTjRD6TYOdV+KAztpveHlEpG0W4eO4BxGNXyei2+e+i4x89vDSKRJUWZA3dOu1vAs0Yy3zGjHCw==","shasum":"12c38ea353995084ab34a3210813bbbfc0612ce4","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-fennel/-/codemirror-lang-fennel-0.1.0.tgz","fileCount":14,"unpackedSize":57320,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGTuAgjGUzn/q1BZCxopMUTARbepdngIeWiFzoFQTUX8AiBRue0jsUmOx9uMitA/wPgkwR5pyRZ9j7n/YnNGZRV20g=="}]},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"directories":{},"maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/codemirror-lang-fennel_0.1.0_1786493343943_0.6197509356749753"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-12T00:09:03.712Z","0.1.0":"2026-08-12T00:09:04.113Z","modified":"2026-08-12T00:09:04.538Z"},"maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"description":"Fennel language support for the CodeMirror code editor","homepage":"https://codincod.com/","keywords":["editor","code"],"repository":{"type":"git","url":"https://codeberg.org/reeven/codemirror-lang-fennel"},"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","readme":"# @codincod/codemirror-lang-fennel [![NPM version](https://img.shields.io/npm/v/@codincod/codemirror-lang-fennel.svg)](https://www.npmjs.org/package/@codincod/codemirror-lang-fennel)\n\n[ [**CHANGELOG**](https://codeberg.org/reeven/codemirror-lang-fennel/src/branch/master/CHANGELOG.md) ]\n\nThis package implements [Fennel](https://fennel-lang.org/) language support for\nthe [CodeMirror](https://codemirror.net/) code editor, using a\n[Lezer](https://lezer.codemirror.net/) grammar written for this package.\n\nFennel had no grammar anywhere: no Lezer parser, no CodeMirror 5 stream mode,\nnothing on npm under any spelling of the name. A `.fnl` file was plain text, or\nit was handed to a Lisp grammar, which is worse in a way that is easy to miss.\n\nWritten in part for [CodinCod](https://codincod.com/), a competitive coding\nplatform, where it colours the editor people solve puzzles in.\n\nThis code is released under an\n[MIT license](https://codeberg.org/reeven/codemirror-lang-fennel/src/branch/master/LICENSE).\n\n## Usage\n\n```javascript\nimport {EditorView, basicSetup} from \"codemirror\"\nimport {fennel} from \"@codincod/codemirror-lang-fennel\"\n\nconst view = new EditorView({\n  parent: document.body,\n  doc: `(fn greet [name]\\n  (print (.. \"hello, \" name)))`,\n  extensions: [basicSetup, fennel()]\n})\n```\n\n## Why not a Lisp grammar\n\nFennel parses clean under one. Everything made of parentheses does, which is\nwhy the number is worth nothing here: a Lisp grammar reads a Fennel file end to\nend and colours almost none of it correctly.\n\n| Fennel writes | A Lisp grammar sees | It is |\n| --- | --- | --- |\n| `:name` | a keyword | a string. Every table key is written this way |\n| `#(+ $1 $2)` | a vector literal | an anonymous function |\n| `[a b]` | a synonym for `(a b)` | a sequential table, and never a call |\n| `{:a 1}` | a synonym for `(a 1)` | a key/value table |\n| `fn`, `local`, `each` | plain symbols | the forms the language is built from |\n| `#t` | a boolean | a function returning `t` |\n\nIt goes the other way too. Fennel has no `#|` comment, no `#\\` character, no\nvector reader, no dotted pair, no unquote-splicing, and one spelling of quote\nwhere Common Lisp has eight.\n\n## How it was decided\n\nEvery rule comes from `src/fennel/parser.fnl` in the compiler rather than from\nthe manual, because the reader is where the surprises are. Three of them shape\nthe grammar:\n\n**`#` is a prefix, and the only character whose meaning depends on what comes\nafter it.** `#(+ $1 $2)` is a function and `(# tbl)` is a length, and a space\nis the whole difference. The reader settles it by reading one byte ahead, and\nso does this grammar, in the one external tokenizer it has.\n\n**A colon token is a string.** The reader turns anything matching `^:.+$` into\nits own tail, which is why `{:a 1}` has the key `\"a\"`. Colouring it as a\nkeyword is the single most visible thing a Lisp grammar gets wrong here.\n\n**`[` and `{` are values.** A sequence and a table are never applied, which\nmeans a symbol at the head of a list is a call every time. A Lisp grammar needs\nreal machinery to find a parameter list before it can stop colouring parameters\nas functions; here the question does not arise.\n\nAlso handled: `~=` and the tilde that starts nothing else, gensym suffixes\n(`x#`), the implicit parameters `$`, `$1`–`$9` and `$...`, varargs, multisyms\n(`tbl.field`, `obj:method`), Lua's numbers with Fennel's `_` separators and the\nnamed infinities, strings that span lines, and the shebang, which is a comment\non the first line and a function call on any other.\n\n## Coverage\n\nMeasured against 12524 published `.fnl` files, gathered from every repository\nGitHub reports as Fennel: **99.62% parse with no error node.**\n\nThe rest of that number matters more than the number. Fennel's own reader was\nrun over the same corpus as an oracle, and it rejects 113 of those files. Every\nsingle file this grammar fails on is one of them:\n\n| | files |\n| --- | --- |\n| corpus | 12524 |\n| rejected by Fennel itself | 113 |\n| **valid Fennel** | **12411** |\n| of those, parsed with no error node | 12411 (100.00%) |\n\nThe 113 are what a corpus of anything gathered by file extension holds: a copy\nof the GPL saved as `LICENSE-GPL.fnl`, a password list, the compiler's own\n`test/bad/` directory of deliberately broken files, and a handful of real\nmistakes nobody compiled.\n\nThis grammar is deliberately more permissive than the reader in the other\ndirection, and accepts 66 files Fennel rejects. Those failures are rules about\nwhitespace before a delimiter, an odd number of values in a table literal, and\nmalformed multisyms: all true of code that is half-typed, which is the state an\neditor spends most of its time looking at.\n","readmeFilename":"README.md","_rev":"1-d40f37fd82c6045a7f4ce51878a9d4ad"}