Motivation
Authoring a Typst package for Typst Universe has a small but error-prone checklist of requirements: manifest fields, license matching, naming rules, README structure, bundle hygiene. Shipping the calendaring package (PR #4910 on typst/packages) required manually walking the typst/packages submission docs and naming rules. A linter that codifies these rules into cofferdam checks would catch issues before opening a PR.
Scope
A new check group (likely a separate crate cofferdam-typst, or an entry under examples-plugins/) that analyzes a directory containing a typst.toml manifest. The unit of analysis is the package directory, not individual .typ files.
Suggested checks
Consistency
Typst.ManifestVersionMatchesDir — manifest package.version matches the parent directory name when in packages/preview/<name>/<version>/.
Typst.ReadmeVersionMatchesManifest — version strings in README.md import examples (@preview/foo:1.2.3) match the manifest version.
Typst.LicenseFileMatchesSPDX — LICENSE content corresponds to the SPDX identifier in the manifest.
Design
Typst.ManifestRequiredFields — name, version, entrypoint, authors, license, description all present.
Typst.PackageNameNotCanonical — name is not in a blacklist of canonical names (calendar, slides, pdf, book, cv, etc.); when violated, suggest a riff. Typst Universe explicitly rejects canonical names.
Typst.PackageNameKebabCase — multi-word names are kebab-case, no underscores, no typst substring.
Typst.DescriptionStyle — terminated with ., no leading A / An , doesn't contain package/template/Typst, ideally 40–60 chars.
Refactor
Typst.RelativeImportInPublishedReadme — README examples should use @preview/<name>:<version> (works for users) rather than ../lib.typ.
Warning
Typst.BundleIncludesPdf — .pdf files at the package root that aren't excluded in the manifest (bloats the Universe bundle).
Typst.LicenseMissing — LICENSE file absent.
Typst.ChangelogMissing — soft warning; not required by Typst but common request from reviewers.
Implementation hints
- New Cargo crate
cofferdam-typst, exposing checks operating on a TypstPackage struct (parsed typst.toml + filesystem scan).
typst.toml parsing via the toml crate; the schema is small.
- Canonical-name blacklist baked in, regenerated periodically from the public list at https://github.com/typst/packages/tree/main/packages/preview .
- LSP and per-file
.typ analysis are out of scope for v1; package-level metadata first.
Open questions
- Built-in crate vs plugin? Built-in feels right because Typst Universe is well-defined and stable, but it would be cofferdam's first non-TypeScript target.
- Severity of
Typst.PackageNameNotCanonical? Universe will reject these PRs, so Design (architectural rule, not stylistic) seems right.
References
Tracked internally as beads issue cd-i255.
Motivation
Authoring a Typst package for Typst Universe has a small but error-prone checklist of requirements: manifest fields, license matching, naming rules, README structure, bundle hygiene. Shipping the
calendaringpackage (PR #4910 on typst/packages) required manually walking the typst/packages submission docs and naming rules. A linter that codifies these rules into cofferdam checks would catch issues before opening a PR.Scope
A new check group (likely a separate crate
cofferdam-typst, or an entry underexamples-plugins/) that analyzes a directory containing atypst.tomlmanifest. The unit of analysis is the package directory, not individual.typfiles.Suggested checks
Consistency
Typst.ManifestVersionMatchesDir— manifestpackage.versionmatches the parent directory name when inpackages/preview/<name>/<version>/.Typst.ReadmeVersionMatchesManifest— version strings inREADME.mdimport examples (@preview/foo:1.2.3) match the manifest version.Typst.LicenseFileMatchesSPDX—LICENSEcontent corresponds to the SPDX identifier in the manifest.Design
Typst.ManifestRequiredFields—name,version,entrypoint,authors,license,descriptionall present.Typst.PackageNameNotCanonical—nameis not in a blacklist of canonical names (calendar,slides,pdf,book,cv, etc.); when violated, suggest a riff. Typst Universe explicitly rejects canonical names.Typst.PackageNameKebabCase— multi-word names are kebab-case, no underscores, notypstsubstring.Typst.DescriptionStyle— terminated with., no leadingA/An, doesn't containpackage/template/Typst, ideally 40–60 chars.Refactor
Typst.RelativeImportInPublishedReadme— README examples should use@preview/<name>:<version>(works for users) rather than../lib.typ.Warning
Typst.BundleIncludesPdf—.pdffiles at the package root that aren'texcluded in the manifest (bloats the Universe bundle).Typst.LicenseMissing—LICENSEfile absent.Typst.ChangelogMissing— soft warning; not required by Typst but common request from reviewers.Implementation hints
cofferdam-typst, exposing checks operating on aTypstPackagestruct (parsedtypst.toml+ filesystem scan).typst.tomlparsing via thetomlcrate; the schema is small..typanalysis are out of scope for v1; package-level metadata first.Open questions
Typst.PackageNameNotCanonical? Universe will reject these PRs, so Design (architectural rule, not stylistic) seems right.References
Tracked internally as beads issue
cd-i255.