Skip to Content

JSDoc banners

@ttsc/banner adds a fixed @packageDocumentation JSDoc banner to the top of every emitted file. Common case: a license / copyright line at the top of your published package.

Install

npm install -D @ttsc/banner

@ttsc/banner ships the ttsc.plugin auto-discovery marker in its package.json, so ttsc picks it up the moment it appears in your dependencies / devDependencies, no compilerOptions.plugins[] entry needed. The banner text still comes from the banner.config.* file below; the plugin errors without one. To turn a discovered plugin off without uninstalling it, declare the tsconfig entry with enabled: false (see Plugin protocol).

Configure

Register the plugin in tsconfig.json (optional with auto-discovery; the explicit entry is equivalent and takes precedence):

// tsconfig.json { "compilerOptions": { "plugins": [ { "transform": "@ttsc/banner" } ] } }

Drop a banner.config.ts next to tsconfig.json:

// banner.config.ts import type { ITtscBannerConfig } from "@ttsc/banner"; export default { text: "License MIT (c) 2026 Acme", } satisfies ITtscBannerConfig;

A banner.config.* file always exports an object with a text string.

The config is a Node module and runs under the module format Node would give it: an explicit .cts/.mts extension decides on its own, and an ambiguous .ts or .js config follows the nearest package.json "type". So __dirname works in a CommonJS package and import.meta.dirname in a "type": "module" package, and Node’s globals need no /// <reference types="node" /> directive as long as @types/node is installed beside the config.

When the system temporary directory contains the TypeScript config directory, including through a link, the evaluator can use the already opened ttsc cache’s identities directory to avoid changing the config directory. On Windows, it also uses identities when TEMP is on another drive, provided the cache is on the config path’s drive. An independent temporary directory keeps its existing placement. If identities is unavailable, the evaluator uses its existing TEMP or nearest node_modules/.cache or config-directory fallback and removes its temporary files when it finishes.

Run ttsc. Every emitted .js and .d.ts gets:

/** * ---------------------------------------------------------------- * License MIT (c) 2026 Acme * * @packageDocumentation */

@ttsc/banner discovers its config by walking upward from the tsconfig directory, looking for banner.config.{ts,cts,mts,js,cjs,mjs,json}. When a build integration compiles through a generated tsconfig outside the project (the bundler adapters do this whenever an alias or a compilerOptions overlay is set), the integration declares the real project root (pluginConfigDir on TtscCompiler) and the walk starts there instead of the temp directory. To point at a specific file instead of relying on auto-discovery, set configFile on the tsconfig entry (a relative path resolves against the same base directory):

// tsconfig.json { "compilerOptions": { "plugins": [ { "transform": "@ttsc/banner", "configFile": "./config/banner.config.ts" } ] } }

If no config file is found, the compile fails, banners are never silently skipped.

Common use cases

  • License headers at the top of every file in a published library.
  • Generated-file warnings: "Generated by codegen. Do not edit by hand."
  • Build provenance: "Built from commit @{COMMIT_SHA}" (interpolation is up to your build script; the banner plugin itself takes a fixed string).

See also

Last updated on