From 83cbefbfa7960d6ff5701d61e22307c52a7a2604 Mon Sep 17 00:00:00 2001 From: Henning Date: Sun, 5 Mar 2023 22:04:25 +0100 Subject: [PATCH] fix: #775 node_modules not ignored on Windows (#802) --- src/utils/path/is-inside-another-path.ts | 21 ++++++++++++++++ src/watch/inclusive-node-watch-file-system.ts | 5 ++-- .../path/is-inside-another-path-unix.spec.ts | 25 +++++++++++++++++++ .../is-inside-another-path-windows.spec.ts | 21 ++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/utils/path/is-inside-another-path.ts create mode 100644 test/unit/utils/path/is-inside-another-path-unix.spec.ts create mode 100644 test/unit/utils/path/is-inside-another-path-windows.spec.ts diff --git a/src/utils/path/is-inside-another-path.ts b/src/utils/path/is-inside-another-path.ts new file mode 100644 index 00000000..76244500 --- /dev/null +++ b/src/utils/path/is-inside-another-path.ts @@ -0,0 +1,21 @@ +import { relative, isAbsolute } from 'path'; + +function isInsideAnotherPath(parent: string, directory: string): boolean { + const relativePart = relative(parent, directory); + // Tested folder is above parent. + if (relativePart.startsWith('..')) { + return false; + } + // Tested folder is the same as parent. + if (relativePart.length === 0) { + return false; + } + // Tested directory has nothing in common with parent. + if (isAbsolute(relativePart)) { + return false; + } + // Last option, must be subfolder. + return true; +} + +export { isInsideAnotherPath }; diff --git a/src/watch/inclusive-node-watch-file-system.ts b/src/watch/inclusive-node-watch-file-system.ts index 110996b1..c8629b13 100644 --- a/src/watch/inclusive-node-watch-file-system.ts +++ b/src/watch/inclusive-node-watch-file-system.ts @@ -1,4 +1,4 @@ -import { extname } from 'path'; +import { extname, relative, isAbsolute } from 'path'; import type { FSWatcher } from 'chokidar'; import chokidar from 'chokidar'; @@ -8,6 +8,7 @@ import type { Compiler } from 'webpack'; import { clearFilesChange, updateFilesChange } from '../files-change'; import { getInfrastructureLogger } from '../infrastructure-logger'; import type { ForkTsCheckerWebpackPluginState } from '../plugin-state'; +import { isInsideAnotherPath } from '../utils/path/is-inside-another-path'; import type { WatchFileSystem } from './watch-file-system'; @@ -30,7 +31,7 @@ function createIsIgnored( } }); ignoredFunctions.push((path: string) => - excluded.some((excludedPath) => path.startsWith(excludedPath)) + excluded.some((excludedPath) => isInsideAnotherPath(excludedPath, path)) ); ignoredFunctions.push((path: string) => BUILTIN_IGNORED_DIRS.some( diff --git a/test/unit/utils/path/is-inside-another-path-unix.spec.ts b/test/unit/utils/path/is-inside-another-path-unix.spec.ts new file mode 100644 index 00000000..6c4051cc --- /dev/null +++ b/test/unit/utils/path/is-inside-another-path-unix.spec.ts @@ -0,0 +1,25 @@ +import { isInsideAnotherPath } from '../../../../src/utils/path/is-inside-another-path'; + +jest.mock('path', () => jest.requireActual('path').posix); + +const unixTests: [string, string, boolean][] = [ + // Identical + ['/foo', '/foo', false], + // Nothing in common + ['/foo', '/bar', false], + // subfolder + ['/foo', '/foo/bar', true], + // parallel + ['/foo', '/foo/../bar', false], + // relative subfolder + ['/foo', '/foo/./bar', true], +]; + +describe('Properly detects ignored sub-folders on Unix', () => { + it('should work on Unix', () => { + unixTests.forEach(([parent, testedPath, expectedResult]) => { + const result = isInsideAnotherPath(parent, testedPath); + expect(result).toEqual(expectedResult); + }); + }); +}); diff --git a/test/unit/utils/path/is-inside-another-path-windows.spec.ts b/test/unit/utils/path/is-inside-another-path-windows.spec.ts new file mode 100644 index 00000000..a0758abc --- /dev/null +++ b/test/unit/utils/path/is-inside-another-path-windows.spec.ts @@ -0,0 +1,21 @@ +import { isInsideAnotherPath } from '../../../../src/utils/path/is-inside-another-path'; + +jest.mock('path', () => jest.requireActual('path').win32); + +const windowsTests: [string, string, boolean][] = [ + // subfolder + ['C:\\Foo', 'C:\\Foo\\Bar', true], + // Nothing in common + ['C:\\Foo', 'C:\\Bar', false], + // Wrong drive. + ['C:\\Foo', 'D:\\Foo\\Bar', false], +]; + +describe('Properly detects ignored sub-folders on Windows', () => { + it('should work on Windows', () => { + windowsTests.forEach(([parent, testedPath, expectedResult]) => { + const result = isInsideAnotherPath(parent, testedPath); + expect(result).toEqual(expectedResult); + }); + }); +});