Story
Alice looks at the top of main.ts and does not like it. Counting the words she typed, hunting for --needs, checking
that a filter is a real filter, writing the help text by hand: it is a page of code about the shape of a command line,
and none of it is about todos. Other people solved this years ago. So she installs Commander, and for the first time
her project has a package.json and a src folder. The commands are now a list of small descriptions, and the help
text writes itself.
It works so well that she wants to give it away. But that is where it gets awkward: her friends would have to install
Bun first, and most of them will not. Then she finds bun build --compile. It puts her code and the whole runtime into
one file that needs nothing else. She sends that file, they run it. No install, no explaining.
Making one of those files for every kind of computer, every time, is exactly the boring work she is bad at remembering.
So she writes it down once, in a file GitHub reads. She lists the machines she cares about, Linux, macOS and Windows,
and the same short recipe runs once for each of them, on its own, at the same time. Every push to main leaves five
finished binaries waiting for her to pick up. She does nothing, and they are simply there.
Alice's Notebook
- Give every command its own function instead of writing its body inside the switch block.
- Keep the code that reads the terminal apart from the code that knows what a todo is.
- Handle different concerns in different parts of the program (Single Responsibility Principle).
- Use a library for the work that is not your program’s real job.
Choose a file from the tree.
;
;
;
;
"todo""a small todo list that lives in a folder"version;
program
"add"
"write down a new todo"
"<title...>", "what you have to do"
"--needs <ids>",
"ids of the todos this one waits for, separated by commas",
","id !== "",
;
program
"list"
"show the todos"
new "[filter]", "which todos to show"todo.filters"all"
filter;
program
"done"
"mark a todo as finished"
"<id>", "the todo you have finished"
;
program
"remove"
"throw a todo away"
"<id>", "the todo you do not want any more"
;
try
catch error
;
;
;
;
;
;
;
;
if !dir dir;
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "todo",
"dependencies": {
"commander": "^15.0.0",
},
"devDependencies": {
"@types/bun": "^1.3.14",
},
},
},
"packages": {
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
"@types/node": ["@types/node@26.2.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg=="],
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
"commander": ["commander@15.0.0", "", {}, "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg=="],
"undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
}
}