Linting — tcm-ts

Linting

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

  • on scratch files: in VS Code as you type (diagnostics with source oxlint), and in tcm check;
  • when you save: tcm add and tcm update show findings in the definitions being saved, and a rule set to "error" stops the save;
  • on the codebase: tcm lint [namespace].
$ 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. --fresh re-lints everything.
  • tcm check and saving lint only new or changed code. A definition saved only because it's in a cycle with one you changed keeps its code, so it isn't linted.

Cached by hash

Findings are cached by a definition's text as tcm view shows it, oxlint's version and the configuration, so linting a whole codebase lints only what's new. The cache key is the text, not just the hash: a comment turning a rule off, or a local renamed _unused, changes findings without changing the hash.

  • Cycles: definitions that refer to each other run as one module. Each is linted as it reads alone, the others imported; what comes only of that (assigning to a let they share, as to an import) isn't reported.
  • What re-lints everything: a configuration change, or a new oxlint (a new tcm's, or one chosen with tcm upgrade oxlint@<range>). oxlint ships with tcm at the version it was tested with.
  • Findings travel with tcm push and tcm pull, as test results do (sync), so another machine doesn't re-lint what was linted with the same oxlint and configuration.

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

lint.config

A definition at lint.config configures linting. 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" },
};
  • JS plugins are imports. The packages lint.config imports are its JS plugins (ESLint-compatible; oxlint's JS plugins). List them under jsPlugins so the import counts as used. tcm provides, pins and upgrades them like any import.
  • It's a definition, so changing it is an update, with history like any code.

Built from c482a14e