Always run linter on specified files during arc diff?

Currently, I’m writing a custom linter that lints TypeScript code using tsc --noEmit to do so.

Given the limitations of tsc, it is impossible to spawn one linter on each files because we would lose compiler config (GitHub issue). The workaround is to run it on one file only (see GH issue) and from there, run it on the whole codebase.

While such a workaround supposedly worked, it only worked because I kept on modifying the included file.
Now that I’ve authored this plugin, I’m realizing this doesn’t work:


  "linters": {
    "tsc": {
      "type": "tsclint",
      "include": "(src/some.config.js)",
      "flags": ["--jsx", "react"]
❯ arc lint --cache 0
No paths are lintable.

However, if I manually pass the file from CLI to arc lint, it works:

❯ arc lint src/some.config.js
 OKAY  No lint warnings.

Is there a way to reproduce this CLI behavior with an .arcconfig entry, so that the linter is always ran ?

Is there a way to reproduce this CLI behavior with an .arcconfig entry, so that the linter is always ran?


There will likely be support for “beautifiers” in the future (see but linters currently need to conform relatively narrowly to the set of behaviors Phabricator expects them to have (roughly: run on one or more input files, emit a list of messages).

You can likely get the behavior you want by doing this:

  • configure your linter to run on all relevant files (likely, all .js files);
  • make your lint binding completely discard the list and run on your single magic file instead, to lint the whole project.


  • when run as arc lint, the whole project will be linted if any .js file is changed;
  • when run as arc lint --everything, the whole project will be linted if it contains any .js files;
  • when run as arc lint with no .js changes, nothing will be linted, but this is expected and consistent with intent.

That’s indeed the solution we went for, but it has caveats.

The thing is an, arc lint with all .js files included would run our fairly heavy script one time per modified file (unless arc lint --lintall magicFile of course).

In that case, I’m not sure ArcanistExternalLinter or ArcanistLintEngine expose methods that would allow to exit the linter after the first run, I haven’t found any. If first run throws, it’s all good, otherwise I think this we have a complexity of O(n), n being the number of modified files.

You suggest “discarding the list and running on our magic file instead”. AFAIK we cannot really change arc lint flags (or even pass an arc alias) when ran in the context of arc diff unless there’s a .arclint config I didn’t see.

An approach is to follow ArcanistFutureLinter roughly, and lint the entire project in willLintPaths(), then do nothing in lintPath(). The linter won’t actually exit after first run, but it will raise messages for every file exactly once.