Deno 2.1.7, Project Idioms
I’ve noticed a collection of file and code idioms I’ve been used in my recent Deno+TypeScript projects at work. I’ve captured them here as a future reference.
Project files
My project generally have the following files, these are derived from the CodeMeta file using CMTools.
- codemeta.json
- Primary source of project metadata, used to generate various files
- CITATION.cff
- used by GitHub for citations. version, dateModified, datePublished and releaseNotes
- about.md
- A project about page. This is generated based on the codemeta.json file.
- README.md, README
- A general read me describing the project and pointing to INSTALL.md, user_manual.md as appropriate
- INSTALL.md
- These are boiler plate description of how to install and compile the software
- user_manual.md
- This is an index document, a table of contents. It points to other document including Markdown versions of the man page(s).
For TypeScript projects I also include a following
- version.ts
- This hold project version information used in the TypeScript co-debase. It is generated from the codemeta.json via CMTools.
- helptext.ts
-
This is where I place a function,
fmtHelp()
, for rendering response to the “help” command line option.
I’m currently ambivalent about “main.ts” file which is created by
deno init
. My ambivalent is that most of my projects wind
up producing more than one program from a shared code base. a single
“main.ts” doesn’t really fit that situation.
The command line tool will have a TypeScript with it’s name. Inside
this file I’ll have a main function and use the Deno idiom
if (import.meta.main) main();
to invoke it. I don’t
generally put the command line TypeScript in my “mod.ts” file since it’s
not going to work in a browser or be useful outside my specific
project.
- mod.ts
- I usually re-export modules here that maybe useful outside my project (or in the web browser).
- deps.ts
- I use this if there are allot of files consistently being imported across the project, otherwise I skip it.
What I put in Main
I use the main function to define command line options, handle parameters such as data input, output and errors. It usually invokes a primary function modeled in the rest of the project code.
Here is an example Main for a simple “cat” like program.
import { parseArgs } from "jsr:@std/cli";
import { licenseText, releaseDate, releaseHash, version } from "./version.ts";
import { fmtHelp, helpText } from "./helptext.ts";
const appName = "mycat";
async function main() {
const app = parseArgs(Deno.args, {
alias: {
help: "h",
license: "l",
version: "v",
},
default: {
help: false,
version: false,
license: false,
},
});
const args = app._;
if (app.help) {
console.log(fmtHelp(helpText, appName, version, releaseDate, releaseHash));
Deno.exit(0);
}
if (app.license) {
console.log(licenseText);
Deno.exit(0);
}
if (app.version) {
console.log(`${appName} ${version} ${releaseHash}`);
Deno.exit(0);
}
let input: Deno.FsFile | any = Deno.stdin;
// handle case of many file names
if (args.length > 1) {
for (const arg of args) {
input = await Deno.open(`${arg}`);
for await (const chunk of input.readable) {
const decoder = new TextDecoder();
console.log(decoder.decode(chunk));
}
}
Deno.exit(0);
}
if (args.length > 0) {
input = await Deno.open(Deno.args[0]);
}
for await (const chunk of input.readable) {
const decoder = new TextDecoder();
console.log(decoder.decode(chunk));
}
}
if (import.meta.main) main();
helptext.ts
The following is an example of the helptext.ts file for the demo mycat.ts.
export function fmtHelp(
txt: string,
appName: string,
version: string,
releaseDate: string,
releaseHash: string,
): string {
return txt.replaceAll("{app_name}", appName).replaceAll("{version}", version)
.replaceAll("{release_date}", releaseDate).replaceAll(
"{release_hash}",
releaseHash,
);
}
export const helpText =
`%{app_name}(1) user manual | version {version} {release_hash}
% R. S. Doiel
% {release_date}
# NAME
{app_name}
# SYNOPSIS
{app_name} FILE [FILE ...] [OPTIONS]
# DESCRIPTION
{app_name} implements a "cat" like program.
# OPTIONS
Options come as the last parameter(s) on the command line.
-h, --help
: display help
-v, --version
: display version
-l, --license
: display license
# EXAMPLES
~~~shell
{app_name} README.md
{app_name} README.md INSTALL.md
~~~
`;
Generating version.ts
The version.ts is generated form two files,
[codemeta.json] and [LICENSE] using the CMTools, cmt
command.
cmt codemeta.json veresion.ts