Skip to content

How to keep other tools off generated files

Set up exact manifest-driven exclusions for Git, formatters, linters, and coverage.

Updated View as Markdown

Hem emits deterministic TypeScript siblings. Their hashed banners protect them from accidental edits: build, watch, and Vite refuse an edited sibling (HEM3008), and hem check catches it without writing. Formatter, linter, and coverage tools should exclude those exact siblings. Authored Hem and handwritten TypeScript keep their ordinary checks; TypeScript and bundlers must still discover the siblings.

Register the consumer root

Build once, then register the project:

hem build
hem generated setup .

Setup writes .hem/tooling.json and adds a hashed managed block to .gitignore and .prettierignore. The block contains only root-anchored paths from .hem/generated-files.json; it never introduces *.ts or *.tsx exclusions. Existing ignore rules and comments stay intact. Commit the registration, manifest, and ignore files. Git ignores affect untracked files; they do not untrack siblings already committed.

For tools configured at a shared repository root, list every participating tsconfig project and specify that root:

hem generated setup packages/invoice packages/db apps/worker --relative-to .

Every project must be contained by the consumer root. Rerunning setup replaces the registration with the supplied project set. Run it again when adding or removing a whole project.

After registration, build, watch, and Vite refresh the managed blocks whenever they update an enrolled project’s manifest. Adding, renaming, or deleting a Hem source changes the exact exclusions automatically. The configuration APIs below read the current manifests each time the tool loads its configuration. Restart a running linter or test server after changing the manifest if that tool does not reload configuration.

On a fresh checkout, ignored siblings may be absent. Configuration can load before the first build: the committed registration and manifest provide exact exclusion paths while their Hem sources exist. Run hem build to regenerate the executable siblings before using them.

Connect lint and coverage configuration once

Setup handles Git and Prettier ignore files directly. It prints the remaining one-time wiring; it does not execute or rewrite JavaScript configuration or arbitrary JSON configuration.

For ESLint flat configuration, add the exported object as a separate global ignore entry. Keep your existing entries:

eslint.config.mjsjs
import { generatedESLintIgnores } from "@hem-lang/cli/generated";

export default [
  generatedESLintIgnores(import.meta.dirname),
  // Your existing ESLint configuration entries.
];

The object contains name and ignores only. Adding files or merging it into a rule configuration changes ESLint’s ignore semantics. Place this configuration at the registered consumer root so its pattern basis matches that root. See ESLint’s global ignore rules.

For Vitest, append Hem’s paths to the coverage defaults and any existing custom exclusions:

vitest.config.mjsjs
import { coverageConfigDefaults, defineConfig } from "vitest/config";
import { generatedExclusions } from "@hem-lang/cli/generated";

export default defineConfig({
  test: {
    coverage: {
      exclude: [
        ...coverageConfigDefaults.exclude,
        ...generatedExclusions(import.meta.dirname, "coverage"),
        // Your existing custom exclusions.
      ],
    },
  },
});

Keep your existing plugins and test options. The Vitest root must match the registered consumer root; a workspace project with another root needs a registration and paths based on that root. Do not replace the library defaults with only generated paths. See Vitest coverage exclusions.

For Biome, enable Git ignore integration in your existing configuration:

biome.jsonjson
{
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  }
}

Use the registered Git root as Biome’s VCS root, setting vcs.root if its configuration lives elsewhere. The managed .gitignore then keeps generated siblings out of Biome’s formatter and linter while handwritten files remain eligible under your other rules. Existing Git ignore rules also apply. See Biome’s VCS configuration.

If you maintain Biome files.includes yourself, generatedExclusions(root, "biome") returns escaped force-ignore entries. Include the ordinary inclusion patterns too. This is a read-only API; it does not update JSON configuration.

Ownership and failure recovery

Setup and the configuration APIs require existing sources and valid manifests. Missing siblings retain their exact exclusions; any existing sibling must have a matching source banner and current body hash. Rebuild older unhashed siblings before registering them. A missing source, edited or handwritten replacement, duplicate ownership, invalid registration, or edited managed block causes a refusal. Setup refuses symlink destinations and stages the managed files as an atomic transaction; a refused transaction preserves the existing consumer files.

Do not edit inside a managed block. To repair one, remove that entire block and rerun setup after inspecting the surrounding user rules. Unreadable files and ambiguous markers are refused. Managed blocks are kept after user rules so a later negation cannot accidentally re-include a generated sibling.

Build synchronization commits the ownership manifest and every enrolled ancestor root’s ignore blocks in one rollback-capable transaction. If validation or that transaction fails, the build reports an error and preserves the previous metadata. Emitted siblings and safe stale-sibling deletion happen before this metadata transaction and are not rolled back. Repair edited configuration using the steps above, or resolve the filesystem failure, then rerun hem build to finish synchronization. A retry uses the existing registration and is idempotent. Failed or refused source compilation does not silently authorize ignoring an unowned replacement. Hem preserves an edited stale sibling for recovery rather than deleting it.

Inspect or validate the manifest

hem generated verify .
hem generated exclusions . --format json

Run verification after building in CI. activate validates the existing pairs and rewrites a noncanonical manifest to canonical bytes. exclusions remains available for inspecting paths or integrating another tool: lines prints project-relative paths, json prints escaped glob entries, and biome prints force-ignore entries. Multiple projects require --relative-to <root>.

Consumer setup does not change Hem’s source discovery or watcher policy. The emitted siblings remain the executable ABI consumed by TypeScript and bundlers.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close