question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Symbolic links are ignored

See original GitHub issue
  • ESLint Version: 7.6.0
  • Node Version: 12.18.0
  • npm Version: 6.14.4

What parser (default, Babel-ESLint, etc.) are you using? @typescript-eslint/parser

Please show your full configuration:

Configuration
{
    "env": {
        "browser": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking"
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "project": ["./tsconfig.json"]
    },
    "plugins": [ "@typescript-eslint" ],
    "rules": {
        "brace-style": ["error", "allman", { "allowSingleLine": true }],
        "eol-last": ["error", "always"],
        "eqeqeq": ["error", "always"],
        "indent": ["error", 4, { "SwitchCase": 1 }],
        "linebreak-style": ["error", "unix"],
        "lines-between-class-members": ["error", "always"],
        "max-len": ["error", { "code": 120 }],
        "new-cap": "error",
        "no-irregular-whitespace": ["off"],
        "no-multiple-empty-lines": "error",
        "no-nested-ternary": "error",
        "no-trailing-spaces": "error",
        "no-unexpected-multiline": ["off"],
        "object-curly-spacing": ["error", "always"],
        "object-property-newline": "error",
        "one-var": ["error", "never"],
        "quotes": ["error", "double"],
        "semi": ["error", "always"],
        "space-before-blocks": ["error", "always"],
        "space-in-parens": ["error", "always"],
        "spaced-comment": ["error", "always", {
            "block": { "balanced": true },
            "exceptions": []
        }],
        "@typescript-eslint/no-empty-interface": ["error", { "allowSingleExtends": true }],
        "@typescript-eslint/no-explicit-any": ["error"],
        "@typescript-eslint/no-floating-promises": ["error"],
        "@typescript-eslint/no-non-null-assertion": ["error"],
        "@typescript-eslint/no-unsafe-assignment": ["error"],
        "@typescript-eslint/no-unsafe-call": ["error"],
        "@typescript-eslint/no-unsafe-member-access": ["error"],
        "@typescript-eslint/no-unsafe-return": ["error"],
        "@typescript-eslint/no-unused-vars": ["error"],
        "@typescript-eslint/restrict-template-expressions": ["error"]
    }
}

What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.

// Not relevant, since files are analysed correctly, but not all files are checked.
# This command is executed from `package.json`, i.e. this code is under the `scripts.lint` property.
eslint --ext ts -c .eslintrc.json src

What did you expect to happen? I’m working on a project which has the following structure of src directory:

src/
    code.ts
    utils/  # Folder with files and subfolders.
    shared/ # Symbolic link to another folder which is not within the `src/` folder.

I’ve some errors in TS files inside src/shared/ directory. I expected errors and warnings from ESLint when running a lint action.

What actually happened? Please include the actual, raw output from ESLint. All files, except those in src/shared/ directory have been checked for errors.

After some research, I’ve identified method _iterateFilesRecursive as problematic in lib/cli-engine/file-enumerator.js file.

Inside that function all entries inside a specific directory are checked if they are a file or a folder. But if entry is a symbolic link, it’s completely ignored.

Currently, I’ve made a workaround to patch aforementioned file with modified version of _iterateFilesRecursive method. Of course, that solution is not good since I’m locked to a specific version of ESLint package.

Modified version of `_iterateFilesRecursive`
    *_iterateFilesRecursive(directoryPath, options) {
        debug(`Enter the directory: ${directoryPath}`);
        const { configArrayFactory } = internalSlotsMap.get(this);

        /** @type {ConfigArray|null} */
        let config = null;

        // Enumerate the files of this directory.
        for (const entry of readdirSafeSync(directoryPath)) {
            const filePath = path.join(directoryPath, entry.name);

            // --- CUSTOM CODE STARTS HERE --- //

            // A decision will be made differently if the path represents a symbolic link.
            let isFile = false;
            let isDirectory = false;

            if (entry.isSymbolicLink()) {
                const fileStat = statSafeSync(filePath);

                if (!fileStat) {
                    continue;
                }

                isFile = fileStat.isFile();
                isDirectory = fileStat.isDirectory();

                if (isFile) {
                    console.log('\nCarefully use symbolic links for files since imports may not be resolved correctly!\n');
                }
            } else {
                isFile = entry.isFile();
                isDirectory = entry.isDirectory();
            }

            // --- CUSTOM CODE ENDS HERE --- //

            // Check if the file is matched.
            if (isFile) { // -- CHANGED FROM `entry.isFile()`
                if (!config) {
                    config = configArrayFactory.getConfigArrayForFile(
                        filePath,

                        /*
                         * We must ignore `ConfigurationNotFoundError` at this
                         * point because we don't know if target files exist in
                         * this directory.
                         */
                        { ignoreNotFoundError: true }
                    );
                }
                const matched = options.selector

                    // Started with a glob pattern; choose by the pattern.
                    ? options.selector.match(filePath)

                    // Started with a directory path; choose by file extensions.
                    : this.isTargetPath(filePath, config);

                if (matched) {
                    const ignored = this._isIgnoredFile(filePath, { ...options, config });
                    const flag = ignored ? IGNORED_SILENTLY : NONE;

                    debug(`Yield: ${entry.name}${ignored ? " but ignored" : ""}`);
                    yield {
                        config: configArrayFactory.getConfigArrayForFile(filePath),
                        filePath,
                        flag
                    };
                } else {
                    debug(`Didn't match: ${entry.name}`);
                }

            // Dive into the sub directory.
            } else if (options.recursive && isDirectory) {  // -- CHANGED FROM `entry.isDirectory()`
                if (!config) {
                    config = configArrayFactory.getConfigArrayForFile(
                        filePath,
                        { ignoreNotFoundError: true }
                    );
                }
                const ignored = this._isIgnoredFile(
                    filePath + path.sep,
                    { ...options, config }
                );

                if (!ignored) {
                    yield* this._iterateFilesRecursive(filePath, options);
                }
            }
        }

        debug(`Leave the directory: ${directoryPath}`);
    }

Are you willing to submit a pull request to fix this bug? Yes.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:13 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
mdjermanoviccommented, Aug 7, 2020

Hi @vjekoart, thanks for the bug report!

Looks like a regression from 2c28fbbb563a44282bef0c9fcc9be29d611cc83b

We were previously using fs.statSync which returns the stat of the link’s target, but fs.readdirSync apparently doesn’t work like that.

0reactions
mdjermanoviccommented, Feb 21, 2021

This will be fixed by #14126

Read more comments on GitHub >

github_iconTop Results From Across the Web

Telling git to ignore symlinks
This seems to be a better idea find . -type l | sed -e s'/^\.\///g' >> .gitignore. Find outputs a "./" prefix for...
Read more >
Git - gitignore Documentation
gitignore - Specifies intentionally untracked files to ignore ... Git does not follow symbolic links when accessing a .gitignore file in the working...
Read more >
Symlinks ignored - Feature
What I can't figure out is why my symlinks get ignored by Syncthing: everything results “in sync”, despite symlinks not being synced at...
Read more >
Symbolic link to python 3.6 is ignored
Symbolic link to python 3.6 is ignored · 1 · I believe @Kusalananda is right, another option is when encountering file or permissions...
Read more >
Option to ignore symlinks (#458) · Issues - meld - GitLab
I would like to suggest an option in Meld to ignore symlinks. As an example, I have a project where there is a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found