Linting — tcm-ts

12. Linting

tcm lints with oxlint, with nothing to install or configure. It runs:

  • on scratch files: in VS Code as diagnostics (source oxlint) as you type, and in tcm check;
  • on what you save: tcm add and tcm update show the findings in the definitions being saved, and a rule set to "error" stops the save;
  • on the codebase: tcm lint [namespace].

tcm check and saving look only at code that's new or changed. A definition in a cycle with one you changed is saved with it and re-hashed, but its code is as it was, so it isn't linted.

$ tcm lint
ui.Pic #uds7r4nm
  2:10  warning  Missing `alt` attribute. jsx-a11y(alt-text)
    return <img src={src} />;
    Must have `alt` prop, either with meaningful text, or an empty string for decorative images.
no errors, 1 warning(s) in 12 definition(s) (11 cached)

Positions are in the definition as tcm view shows it. tcm lint exits with 1 when there are errors.

12.1 Cached by hash

A definition's findings depend only on its text as tcm view shows it, the linter's version and the configuration, so they're cached by those: linting a whole codebase lints what's new. (The text, not just the hash: a comment that turns a rule off, or a local renamed _unused, changes what's found without changing the hash.) Definitions that refer to each other run as one module, and each is linted as tcm view shows it, the others imported; what only comes of that (assigning to a let they share, as to an import) isn't reported. Changing the configuration or oxlint's version (a new tcm's, or another chosen for the codebase with tcm upgrade oxlint@<range>) lints everything again. oxlint comes with tcm, at the version tcm was tested with, so there's nothing to install. --fresh re-lints regardless. Findings travel with tcm push and tcm pull, as test results do (sync), so a clone or another machine doesn't lint again what was linted elsewhere with the same linter and configuration.

12.2 What's checked

oxlint's correctness rules, as warnings, plus its plugins for what the code uses:

any
typescript, unicorn, oxc
JSX
react, jsx-a11y
tests
vitest
Node builtins (node:fs, …)
node

12.3 lint.config

A definition at lint.config configures it. Its value is oxlint configuration: rules, categories, plugins (oxlint's built-in ones) and settings.

// tcm: namespace lint
import noOnlyTests from "eslint-plugin-no-only-tests";

export const config = {
  jsPlugins: [noOnlyTests],
  categories: { suspicious: "warn" },
  rules: { "no-debugger": "error", "no-only-tests/no-only-tests": "error" },
};

Plugins are imports. The packages lint.config imports are its JS plugins (ESLint-compatible ones; oxlint's JS plugins). List them under jsPlugins, so the import counts as used. Like any import they're provided, pinned and upgraded by tcm. Since the configuration is a definition, changing it is an update, and its history is the codebase's.

built from c482a14e