xo icon indicating copy to clipboard operation
xo copied to clipboard

File matching to determine generated tsconfig does not take relative directories into account

Open mcous opened this issue 3 years ago • 0 comments

Overview

xo attempts to check if a given file that it's linting matches a tsconfig.json passed into parserOptions.project. If the file being checked does not match the tsconfig (according to minimatch), a temporary tsconfig will be created.

https://github.com/xojs/xo/blob/352f20c0b0572c674f519cdf98a46fa0f35a96d9/lib/options-manager.js#L178-L181

However, options.filePath here is an absolute filepath, and the includes glob of a given tsconfig.json may be specified as a relative path from the config file itself. If the tsconfig in question is not in the current working directory, this check will erroneously fail.

I noticed this issue due to xojs/vscode-linter-xo#110. I thought I had given xo a good parserOptions.project path, but xo and the vscode-linter-xo started generating competing (and different!) temporary tsconfigs in the cache, eventually causing the editor extension to start choking on parser errors.

Reproduction

Project structure

- my-project/
    - package.json 
    - config/
        - tsconfig.lint.json
    - src/
        - some-file.ts

tsconfig.lint.json

{
  ...
  "include": ["../src/**/*"]
}

Behavior

/path/to/my-project/src/some-file.ts does not match the glob ../src/**/*, so a temporary tsconfig is created in node_modules/.cache/xo-linter, even though tsc would recognize the config as matching that file.

{
  "extends": "/path/to/my-project/config/tsconfig.lint.json",
  "files": ["/path/to/my-project/src/some-file.ts"],
  "include": [],
  "exclude": []
}

Proposal

Before passing options.filePath to micromatch, I think it should be made relative to options.tsConfigPath if it exists. If this is an acceptable solution, I'm happy open a PR!

micromatch.contains("/path/to/my-project/src/some-file.ts", ["src/**/*"])
> true
micromatch.contains("/path/to/my-project/src/some-file.ts", ["../src/**/*"])
> false
micromatch.contains("../src/some-file.ts", ["../src/**/*"])
> true

Workaround

This issue is pretty straightforward to workaround by placing the tsconfig given to parserOptions.project in the project root rather than a subdirectory, so that a glob like src/**/* will match an absolute path.

mcous avatar Apr 28 '22 00:04 mcous