Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

rulesDirectory in extended configuration should also be resolved against the current dir #3827

Closed
MateuszStefek opened this issue Apr 10, 2018 · 4 comments

Comments

@MateuszStefek
Copy link

Bug Report

  • TSLint version: 2.9.1
  • TypeScript version: 2.6.2
  • Running TSLint via: CLI

I have a company-wide tslint configuration which is used by various projects via "extends" configuration.

I don't seem to be able to configure tslint-defocus to be included in the shared configuration.

The shared configuration:

{
  "defaultSeverity": "warning",
  "extends": "tslint-eslint-rules",
  "rulesDirectory": [
    "codelyzer",
    "./node_modules/tslint-defocus/dist"
  ],

Projects use this configuration in the following way:

{
  "extends": [
    "shared-configuration"
  ],

This is not an npm problem. tslint-defocus gets correctly installed in node_modules in the projects, but every time I run tslint in such project, I get the following error:

 ng lint

Failed to load AAA\tslint.json: Could not find custom rule directory: ./node_modules/tslint-defocus/dist
FatalError: Failed to load AAA\tslint.json: Could not find custom rule directory: ./node_modules/tslint-defocus/dist
    at new FatalError (C:\Users\matste\uptime\uptime\ui\ui-frontend\node_modules\tslint\lib\error.js:27:28)
    at Object.findConfiguration (C:\Users\matste\uptime\uptime\ui\ui-frontend\node_modules\tslint\lib\configuration.js:55:15)
    at lintConfigs.map (C:\Users\matste\uptime\uptime\ui\ui-frontend\node_modules\@angular\cli\tasks\lint.js:67:48)
    at Array.map (<anonymous>)

I tried all options: node_modules/tslint-defocus/dist, tslint-defocus/dist.

Looking at the code of the configuration.ts, it seems that when tslint sees tslint-defocus/dist, it first try to resolve it as a node module and fails predictably (the module is called 'tslint-defocus', not 'tslint-defocus/dist'). Then it tries to resolve it as a local path, but tslint resolves it relative to where the shared configuration is installed (relativeTo !== undefined).

export function getRulesDirectories(directories?: string | string[], relativeTo?: string): string[] {
    return arrayify(directories)
        .map((dir) => {
            if (!useAsPath(dir)) {
                try {
                    return path.dirname(resolve.sync(dir, { basedir: relativeTo }));
                } catch (err) {
                    // swallow error and fallback to using directory as path
                }
            }

            const absolutePath = relativeTo === undefined ? path.resolve(dir) : path.resolve(relativeTo, dir);
            if (absolutePath !== undefined) {
                if (!fs.existsSync(absolutePath)) {
                    throw new FatalError(`Could not find custom rule directory: ${dir}`);
                }
            }
            return absolutePath;
        });
}

In my opinion, tslint should also try local path (ignoring relativeTo), when the above options fail.

@renataogarcia
Copy link

You could give it a go on a more recent version - I think this is available since 5.2.0

@Adjective-Object
Copy link

Tried on 5.11.0, running into the same issue.

Does getRulesDirectories ever get called relative to the extending config's directory? If so I'm not seeing it :/

@aleclarson
Copy link

aleclarson commented Nov 8, 2018

Also hitting this on 5.11.0.

The rulesDirectory paths should be resolved relative to the extended package, not the extending package (which is what seems to be happening).

As a workaround, you can use the name of the extended package inside its own config.

{
  "rulesDirectory": [
    "tslint-foo/node_modules/tslint-defocus/dist"
  ]
}

My guess is that TSLint just deeply merges extended configs without processing them first.

@aleclarson
Copy link

This bug is fixed in 5.14.0 🎉

(not sure about 5.12.x or 5.13.x)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants