Utility to generate jsr.json files
MIT License
Utility to update the deno.json
file with the fields required to publish to
JSR. Useful specially to generate exports
and version
fields automatically.
Run this code changing the PKG-NAME
with the name of the package you want to
publish:
deno run -A https://deno.land/x/[email protected]/mod.ts --name=PKG-NAME
It generates the fields name
, version
and exports
in your deno.json
file.
name
field is the same value passed as CLI argument.version
value is detected automatically from the most recent tag in theexports
value is generated by scanning your code (more info below).Then, you can run deno publish --allow-dirty
to send the package to JSR.
exports
are generated?The exports
field of JSR allows to change the real files of your modules. This
is used to provide extensionless specifiers. For example:
{
"name": "@my/package",
"version": "1.0.0",
"exports": {
".": "./main.ts",
"./first-module": "./first_module.ts",
"./second-module": "./second_module.ts"
}
}
Now, you can import these modules with @my/package/first-module
which returns
the file ./first_module.ts
.
This has several issues:
The package is not longer compatible with the file system. For example, you cannot use a local version of this package for debuging purposes, because the paths of the modules are different.
You don't know the real format of the file you're importing. This is specially critical for the new import attributes standard that allows to import different types of modules like JSON, CSS etc.
This is not compatible with web standards and makes more difficult to switch to HTTP imports in the future. It makes harder to create modules that work on Deno and browsers.
It's an antipattern that even Node (which originally started this trend) now recommends to avoid:
With import maps now providing a standard for package resolution in browsers and other JavaScript runtimes, using the extensionless style can result in bloated import map definitions. Explicit file extensions can avoid this issue by enabling the import map to utilize a packages folder mapping to map multiple subpaths where possible instead of a separate map entry per package subpath export. This also mirrors the requirement of using the full specifier path in relative and absolute import specifiers.
It overlaps the import maps standard. For example, in Deno it's really painful to combine JSR and import maps.
For large projects, is hard to maintain the list of exports, specially if you
want to let import all or almost all files. It's common to forget to add a new
module to the exports
list.
This script fixes this problem by generating exports compatible with regular HTTP and file system imports:
.ts
, .js
, .tsx
,.jsx
and .mjs
./test/
, /docs/
, /deps/
or /node_modules/
..
or _
or is in a directory starting with .
or_
..test.*
, _test.*
, .bench.*
, _bench.*
.deps.*
.exports
field keeping the filename intact, without removingFor example, the following project:
├── docs/
| ├── one.js
| └── two.ts
├── test/
| ├── one.js
| └── two.ts
├── mod.ts
├── one.js
├── one.bench.js
├── two.ts
└── two.bench.ts
Generate the following exports:
{
"exports": {
".": "./mod.ts",
"./one.js": "./one.js",
"./two.ts": "./two.ts"
}
}
The mod.*
file is automatically detected as the main module.
Now the specifiers in JSR are compatible with the filesystem, so it's possible to switch to local imports or http imports easily at any time. For example, the following import:
import one from "my_package/one.js";
Is compatible with any origin type, by editing the import map:
{
imports: {
"my_package/": "jsr:@my/package/", // to use JSR
"my_package/": "./vendor/my/package/", // to use local file system
"my_package/": "https://deno.land/x/my_package/", // to use HTTP imports
}
}