diff --git a/lib/chunkFiles.js b/lib/chunkFiles.js index 64761a046..3e5a20ccf 100644 --- a/lib/chunkFiles.js +++ b/lib/chunkFiles.js @@ -1,7 +1,8 @@ import path from 'node:path' import debug from 'debug' -import normalize from 'normalize-path' + +import { normalizePath } from './normalizePath.js' const debugLog = debug('lint-staged:chunkFiles') @@ -35,7 +36,7 @@ const chunkArray = (arr, chunkCount) => { */ export const chunkFiles = ({ files, baseDir, maxArgLength = null, relative = false }) => { const normalizedFiles = files.map((file) => - normalize(relative || !baseDir ? file : path.resolve(baseDir, file)) + normalizePath(relative || !baseDir ? file : path.resolve(baseDir, file)) ) if (!maxArgLength) { diff --git a/lib/generateTasks.js b/lib/generateTasks.js index b05d625f3..0d6b5017c 100644 --- a/lib/generateTasks.js +++ b/lib/generateTasks.js @@ -2,7 +2,8 @@ import path from 'node:path' import debug from 'debug' import micromatch from 'micromatch' -import normalize from 'normalize-path' + +import { normalizePath } from './normalizePath.js' const debugLog = debug('lint-staged:generateTasks') @@ -19,7 +20,7 @@ const debugLog = debug('lint-staged:generateTasks') export const generateTasks = ({ config, cwd = process.cwd(), files, relative = false }) => { debugLog('Generating linter tasks') - const relativeFiles = files.map((file) => normalize(path.relative(cwd, file))) + const relativeFiles = files.map((file) => normalizePath(path.relative(cwd, file))) return Object.entries(config).map(([pattern, commands]) => { const isParentDirPattern = pattern.startsWith('../') @@ -42,7 +43,7 @@ export const generateTasks = ({ config, cwd = process.cwd(), files, relative = f strictBrackets: true, }) - const fileList = matches.map((file) => normalize(relative ? file : path.resolve(cwd, file))) + const fileList = matches.map((file) => normalizePath(relative ? file : path.resolve(cwd, file))) const task = { pattern, commands, fileList } debugLog('Generated task: \n%O', task) diff --git a/lib/getStagedFiles.js b/lib/getStagedFiles.js index 8cbb83bb9..2500efc80 100644 --- a/lib/getStagedFiles.js +++ b/lib/getStagedFiles.js @@ -1,9 +1,8 @@ import path from 'node:path' -import normalize from 'normalize-path' - import { execGit } from './execGit.js' import { getDiffCommand } from './getDiffCommand.js' +import { normalizePath } from './normalizePath.js' import { parseGitZOutput } from './parseGitZOutput.js' export const getStagedFiles = async ({ cwd = process.cwd(), diff, diffFilter } = {}) => { @@ -11,7 +10,7 @@ export const getStagedFiles = async ({ cwd = process.cwd(), diff, diffFilter } = const lines = await execGit(getDiffCommand(diff, diffFilter), { cwd }) if (!lines) return [] - return parseGitZOutput(lines).map((file) => normalize(path.resolve(cwd, file))) + return parseGitZOutput(lines).map((file) => normalizePath(path.resolve(cwd, file))) } catch { return null } diff --git a/lib/normalizePath.js b/lib/normalizePath.js new file mode 100644 index 000000000..562c57a7f --- /dev/null +++ b/lib/normalizePath.js @@ -0,0 +1,50 @@ +/** + * Reimplementation of "normalize-path" + * @see https://github.com/jonschlinkert/normalize-path/blob/52c3a95ebebc2d98c1ad7606cbafa7e658656899/index.js + */ + +/*! + * normalize-path + * + * Copyright (c) 2014-2018, Jon Schlinkert. + * Released under the MIT License. + */ + +import path from 'node:path' + +/** + * A file starting with \\?\ + * @see https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#win32-file-namespaces + */ +const WIN32_FILE_NS = '\\\\?\\' + +/** + * A file starting with \\.\ + * @see https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#win32-file-namespaces + */ +const WIN32_DEVICE_NS = '\\\\.\\' + +/** + * Normalize input file path to use POSIX separators + * @param {String} input + * @returns String + */ +export const normalizePath = (input) => { + if (input === path.posix.sep || input === path.win32.sep) { + return path.posix.sep + } + + let normalized = input.split(/[/\\]+/).join(path.posix.sep) + + /** Handle win32 Namespaced paths by changing e.g. \\.\ to //./ */ + if (input.startsWith(WIN32_FILE_NS) || input.startsWith(WIN32_DEVICE_NS)) { + normalized = normalized.replace(/^\/(\.|\?)/, '//$1') + } + + /** Remove trailing slash */ + if (normalized.endsWith(path.posix.sep)) { + normalized = normalized.slice(0, -1) + } + + return normalized +} diff --git a/lib/resolveGitRepo.js b/lib/resolveGitRepo.js index f01570590..fbd28ce63 100644 --- a/lib/resolveGitRepo.js +++ b/lib/resolveGitRepo.js @@ -2,10 +2,10 @@ import fs from 'node:fs/promises' import path from 'node:path' import debug from 'debug' -import normalize from 'normalize-path' import { execGit } from './execGit.js' import { readFile } from './file.js' +import { normalizePath } from './normalizePath.js' const debugLog = debug('lint-staged:resolveGitRepo') @@ -15,7 +15,7 @@ const debugLog = debug('lint-staged:resolveGitRepo') */ const resolveGitConfigDir = async (gitDir) => { // Get the real path in case it's a symlink - const defaultDir = normalize(await fs.realpath(path.join(gitDir, '.git'))) + const defaultDir = normalizePath(await fs.realpath(path.join(gitDir, '.git'))) const stats = await fs.lstat(defaultDir) // If .git is a directory, use it if (stats.isDirectory()) return defaultDir @@ -33,10 +33,10 @@ export const determineGitDir = (cwd, relativeDir) => { } if (relativeDir) { // the current working dir is inside the git top-level directory - return normalize(cwd.substring(0, cwd.lastIndexOf(relativeDir))) + return normalizePath(cwd.substring(0, cwd.lastIndexOf(relativeDir))) } else { // the current working dir is the top-level git directory - return normalize(cwd) + return normalizePath(cwd) } } @@ -55,9 +55,9 @@ export const resolveGitRepo = async (cwd = process.cwd()) => { // read the path of the current directory relative to the top-level directory // don't read the toplevel directly, it will lead to an posix conform path on non posix systems (cygwin) - const gitRel = normalize(await execGit(['rev-parse', '--show-prefix'], { cwd })) - const gitDir = determineGitDir(normalize(cwd), gitRel) - const gitConfigDir = normalize(await resolveGitConfigDir(gitDir)) + const gitRel = normalizePath(await execGit(['rev-parse', '--show-prefix'], { cwd })) + const gitDir = determineGitDir(normalizePath(cwd), gitRel) + const gitConfigDir = normalizePath(await resolveGitConfigDir(gitDir)) debugLog('Resolved git directory to be `%s`', gitDir) debugLog('Resolved git config directory to be `%s`', gitConfigDir) diff --git a/lib/runAll.js b/lib/runAll.js index ab06f6889..819e5daf4 100644 --- a/lib/runAll.js +++ b/lib/runAll.js @@ -5,7 +5,6 @@ import path from 'node:path' import chalk from 'chalk' import debug from 'debug' import { Listr } from 'listr2' -import normalize from 'normalize-path' import { chunkFiles } from './chunkFiles.js' import { execGit } from './execGit.js' @@ -24,6 +23,7 @@ import { SKIPPED_GIT_ERROR, skippingBackup, } from './messages.js' +import { normalizePath } from './normalizePath.js' import { resolveGitRepo } from './resolveGitRepo.js' import { applyModificationsSkipped, @@ -160,7 +160,7 @@ export const runAll = async ( const matchedFiles = new Set() for (const [configPath, { config, files }] of Object.entries(filesByConfig)) { - const configName = configPath ? normalize(path.relative(cwd, configPath)) : 'Config object' + const configName = configPath ? normalizePath(path.relative(cwd, configPath)) : 'Config object' const stagedFileChunks = chunkFiles({ baseDir: gitDir, files, maxArgLength, relative }) @@ -193,7 +193,7 @@ export const runAll = async ( // relative filenames in the entire set. const normalizedFile = path.isAbsolute(file) ? file - : normalize(path.join(groupCwd, file)) + : normalizePath(path.join(groupCwd, file)) matchedFiles.add(normalizedFile) }) diff --git a/lib/searchConfigs.js b/lib/searchConfigs.js index dce5b0dbc..9c860eb6e 100644 --- a/lib/searchConfigs.js +++ b/lib/searchConfigs.js @@ -3,10 +3,10 @@ import path from 'node:path' import debug from 'debug' -import normalize from 'normalize-path' import { execGit } from './execGit.js' import { loadConfig, searchPlaces } from './loadConfig.js' +import { normalizePath } from './normalizePath.js' import { parseGitZOutput } from './parseGitZOutput.js' import { validateConfig } from './validateConfig.js' @@ -21,7 +21,7 @@ const numberOfLevels = (file) => file.split('/').length const sortDeepestParth = (a, b) => (numberOfLevels(a) > numberOfLevels(b) ? -1 : 1) -const isInsideDirectory = (dir) => (file) => file.startsWith(normalize(dir)) +const isInsideDirectory = (dir) => (file) => file.startsWith(normalizePath(dir)) /** * Search all config files from the git repository, preferring those inside `cwd`. @@ -68,7 +68,7 @@ export const searchConfigs = async ( /** Sort possible config files so that deepest is first */ const possibleConfigFiles = [...cachedFiles, ...otherFiles] - .map((file) => normalize(path.join(gitDir, file))) + .map((file) => normalizePath(path.join(gitDir, file))) .filter(isInsideDirectory(cwd)) .sort(sortDeepestParth) diff --git a/package-lock.json b/package-lock.json index 723582228..c6cbfb29a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "lilconfig": "2.1.0", "listr2": "6.6.1", "micromatch": "4.0.5", - "normalize-path": "3.0.0", "object-inspect": "1.12.3", "pidtree": "0.6.0", "string-argv": "0.3.2", @@ -7330,6 +7329,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index f058fd12a..d12ce0958 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "lilconfig": "2.1.0", "listr2": "6.6.1", "micromatch": "4.0.5", - "normalize-path": "3.0.0", "object-inspect": "1.12.3", "pidtree": "0.6.0", "string-argv": "0.3.2", diff --git a/test/integration/__utils__/createTempDir.js b/test/integration/__utils__/createTempDir.js index f8efbde80..eed566d4f 100644 --- a/test/integration/__utils__/createTempDir.js +++ b/test/integration/__utils__/createTempDir.js @@ -3,7 +3,7 @@ import fs from 'node:fs/promises' import os from 'node:os' import path from 'node:path' -import normalize from 'normalize-path' +import { normalizePath } from '../../../lib/normalizePath.js' /** * Create temporary random directory and return its path @@ -17,5 +17,5 @@ export const createTempDir = async () => { const tempDir = path.join(baseDir, 'lint-staged', crypto.randomUUID()) await fs.mkdir(tempDir, { recursive: true }) - return normalize(tempDir) + return normalizePath(tempDir) } diff --git a/test/integration/multiple-config-files.test.js b/test/integration/multiple-config-files.test.js index 25520795b..70387e512 100644 --- a/test/integration/multiple-config-files.test.js +++ b/test/integration/multiple-config-files.test.js @@ -4,7 +4,8 @@ import './__mocks__/dynamicImport.js' import path from 'node:path' import { jest as jestGlobals } from '@jest/globals' -import normalize from 'normalize-path' + +import { normalizePath } from '../../lib/normalizePath.js' import { withGitIntegration } from './__utils__/withGitIntegration.js' @@ -84,11 +85,11 @@ describe('lint-staged', () => { expect(await readFile('deeper/even/file.js')).toMatch('file.js') // 'deeper/even/deeper/file.js' is relative to parent 'deeper/even/' - expect(await readFile('deeper/even/deeper/file.js')).toMatch(normalize('deeper/file.js')) + expect(await readFile('deeper/even/deeper/file.js')).toMatch(normalizePath('deeper/file.js')) // 'a/very/deep/file/path/file.js' is relative to root '.' expect(await readFile('a/very/deep/file/path/file.js')).toMatch( - normalize('a/very/deep/file/path/file.js') + normalizePath('a/very/deep/file/path/file.js') ) }) ) diff --git a/test/unit/chunkFiles.spec.js b/test/unit/chunkFiles.spec.js index db6491975..58622e452 100644 --- a/test/unit/chunkFiles.spec.js +++ b/test/unit/chunkFiles.spec.js @@ -1,12 +1,11 @@ import path from 'node:path' -import normalize from 'normalize-path' - import { chunkFiles } from '../../lib/chunkFiles.js' +import { normalizePath } from '../../lib/normalizePath.js' describe('chunkFiles', () => { const files = ['example.js', 'foo.js', 'bar.js', 'foo/bar.js'] - const baseDir = normalize('/opt/git/example.git') + const baseDir = normalizePath('/opt/git/example.git') it('should default to sane value', () => { const chunkedFiles = chunkFiles({ baseDir, files: ['foo.js'], relative: true }) @@ -20,7 +19,7 @@ describe('chunkFiles', () => { it('should chunk too long argument string', () => { const chunkedFiles = chunkFiles({ baseDir, files, maxArgLength: 20, relative: false }) - expect(chunkedFiles).toEqual(files.map((file) => [normalize(path.resolve(baseDir, file))])) + expect(chunkedFiles).toEqual(files.map((file) => [normalizePath(path.resolve(baseDir, file))])) }) it('should take into account relative setting', () => { @@ -33,11 +32,11 @@ describe('chunkFiles', () => { it('should resolve absolute paths by default', () => { const chunkedFiles = chunkFiles({ baseDir, files }) - expect(chunkedFiles).toEqual([files.map((file) => normalize(path.resolve(baseDir, file)))]) + expect(chunkedFiles).toEqual([files.map((file) => normalizePath(path.resolve(baseDir, file)))]) }) it('should resolve absolute paths by default even when maxArgLength is set', () => { const chunkedFiles = chunkFiles({ baseDir, files, maxArgLength: 262144 }) - expect(chunkedFiles).toEqual([files.map((file) => normalize(path.resolve(baseDir, file)))]) + expect(chunkedFiles).toEqual([files.map((file) => normalizePath(path.resolve(baseDir, file)))]) }) }) diff --git a/test/unit/generateTasks.spec.js b/test/unit/generateTasks.spec.js index c25645268..a1cc5b19e 100644 --- a/test/unit/generateTasks.spec.js +++ b/test/unit/generateTasks.spec.js @@ -1,11 +1,10 @@ import path from 'node:path' -import normalize from 'normalize-path' - import { generateTasks } from '../../lib/generateTasks.js' +import { normalizePath } from '../../lib/normalizePath.js' // Windows filepaths -const normalizePath = (input) => normalize(path.resolve('/', input)) +const normalizeWindowsPath = (input) => normalizePath(path.resolve('/', input)) const cwd = '/repo' @@ -87,7 +86,7 @@ describe('generateTasks', () => { `/repo/deeper/test2.js`, `/repo/even/deeper/test.js`, `/repo/.hidden/test.js`, - ].map(normalizePath), + ].map(normalizeWindowsPath), }) }) @@ -103,7 +102,7 @@ describe('generateTasks', () => { `/repo/deeper/test2.js`, `/repo/even/deeper/test.js`, `/repo/.hidden/test.js`, - ].map(normalizePath), + ].map(normalizeWindowsPath), }) }) @@ -113,7 +112,7 @@ describe('generateTasks', () => { expect(linter).toEqual({ pattern: 'deeper/*.js', commands: 'deeper-js', - fileList: [`/repo/deeper/test.js`, `/repo/deeper/test2.js`].map(normalizePath), + fileList: [`/repo/deeper/test.js`, `/repo/deeper/test2.js`].map(normalizeWindowsPath), }) }) @@ -123,7 +122,7 @@ describe('generateTasks', () => { expect(linter).toEqual({ pattern: '.hidden/*.js', commands: 'hidden-js', - fileList: [`/repo/.hidden/test.js`].map(normalizePath), + fileList: [`/repo/.hidden/test.js`].map(normalizeWindowsPath), }) }) @@ -144,7 +143,7 @@ describe('generateTasks', () => { `/repo/deeper/test2.css`, `/repo/even/deeper/test.css`, `/repo/.hidden/test.css`, - ].map(normalizePath), + ].map(normalizeWindowsPath), }) }) @@ -163,7 +162,7 @@ describe('generateTasks', () => { expect(linter).toEqual({ pattern: 'test{1..2}.css', commands: 'lint', - fileList: [`/repo/deeper/test1.css`, `/repo/deeper/test2.css`].map(normalizePath), + fileList: [`/repo/deeper/test1.css`, `/repo/deeper/test2.css`].map(normalizeWindowsPath), }) }) @@ -177,7 +176,7 @@ describe('generateTasks', () => { expect(linter).toEqual({ pattern: '*.js', commands: 'root-js', - fileList: [`/repo/deeper/test.js`, `/repo/deeper/test2.js`].map(normalizePath), + fileList: [`/repo/deeper/test.js`, `/repo/deeper/test2.js`].map(normalizeWindowsPath), }) }) @@ -190,7 +189,7 @@ describe('generateTasks', () => { const linter = result.find((item) => item.pattern === '../*.{css,js}') expect(linter).toEqual({ commands: 'parent-dir-css-or-js', - fileList: [`/repo/test.js`, `/repo/test.css`].map(normalizePath), + fileList: [`/repo/test.js`, `/repo/test.css`].map(normalizeWindowsPath), pattern: '../*.{css,js}', }) }) diff --git a/test/unit/getStagedFiles.spec.js b/test/unit/getStagedFiles.spec.js index 40f693939..901c0c5dc 100644 --- a/test/unit/getStagedFiles.spec.js +++ b/test/unit/getStagedFiles.spec.js @@ -1,14 +1,13 @@ import path from 'node:path' -import normalize from 'normalize-path' - -import { getStagedFiles } from '../../lib/getStagedFiles.js' import { execGit } from '../../lib/execGit.js' +import { getStagedFiles } from '../../lib/getStagedFiles.js' +import { normalizePath } from '../../lib/normalizePath.js' jest.mock('../../lib/execGit.js') // Windows filepaths -const normalizePath = (input) => normalize(path.resolve('/', input)) +const normalizeWindowsPath = (input) => normalizePath(path.resolve('/', input)) describe('getStagedFiles', () => { afterEach(() => { @@ -19,7 +18,7 @@ describe('getStagedFiles', () => { execGit.mockImplementationOnce(async () => 'foo.js\u0000bar.js\u0000') const staged = await getStagedFiles({ cwd: '/' }) // Windows filepaths - expect(staged).toEqual([normalizePath('/foo.js'), normalizePath('/bar.js')]) + expect(staged).toEqual([normalizeWindowsPath('/foo.js'), normalizeWindowsPath('/bar.js')]) expect(execGit).toHaveBeenLastCalledWith( ['diff', '--name-only', '-z', '--diff-filter=ACMR', '--staged'], @@ -45,7 +44,7 @@ describe('getStagedFiles', () => { execGit.mockImplementationOnce(async () => 'foo.js\u0000bar.js\u0000') const staged = await getStagedFiles({ cwd: '/', diff: 'master...my-branch' }) // Windows filepaths - expect(staged).toEqual([normalizePath('/foo.js'), normalizePath('/bar.js')]) + expect(staged).toEqual([normalizeWindowsPath('/foo.js'), normalizeWindowsPath('/bar.js')]) expect(execGit).toHaveBeenLastCalledWith( ['diff', '--name-only', '-z', '--diff-filter=ACMR', 'master...my-branch'], @@ -57,7 +56,7 @@ describe('getStagedFiles', () => { execGit.mockImplementationOnce(async () => 'foo.js\u0000bar.js\u0000') const staged = await getStagedFiles({ cwd: '/', diff: 'master my-branch' }) // Windows filepaths - expect(staged).toEqual([normalizePath('/foo.js'), normalizePath('/bar.js')]) + expect(staged).toEqual([normalizeWindowsPath('/foo.js'), normalizeWindowsPath('/bar.js')]) expect(execGit).toHaveBeenLastCalledWith( ['diff', '--name-only', '-z', '--diff-filter=ACMR', 'master', 'my-branch'], @@ -69,7 +68,7 @@ describe('getStagedFiles', () => { execGit.mockImplementationOnce(async () => 'foo.js\u0000bar.js\u0000') const staged = await getStagedFiles({ cwd: '/', diffFilter: 'ACDMRTUXB' }) // Windows filepaths - expect(staged).toEqual([normalizePath('/foo.js'), normalizePath('/bar.js')]) + expect(staged).toEqual([normalizeWindowsPath('/foo.js'), normalizeWindowsPath('/bar.js')]) expect(execGit).toHaveBeenLastCalledWith( ['diff', '--name-only', '-z', '--diff-filter=ACDMRTUXB', '--staged'], diff --git a/test/unit/normalizePath.spec.js b/test/unit/normalizePath.spec.js new file mode 100644 index 000000000..0a5c629ec --- /dev/null +++ b/test/unit/normalizePath.spec.js @@ -0,0 +1,59 @@ +/** + * Reimplementation of "normalize-path" + * @see https://github.com/jonschlinkert/normalize-path/blob/52c3a95ebebc2d98c1ad7606cbafa7e658656899/test.js + */ + +/*! + * normalize-path + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Licensed under the MIT License + */ + +import { normalizePath } from '../../lib/normalizePath' + +describe('normalizePath', () => { + describe('single slash', () => { + it('should always return a single forward slash', () => { + expect(normalizePath('/')).toEqual('/') + expect(normalizePath('\\')).toEqual('/') + }) + }) + + describe('strip trailing slashes', () => { + it.each([ + ['../../foo/bar', '../../foo/bar'], + ['..\\..\\foo/bar', '../../foo/bar'], + ['..\\\\..\\\\foo/bar', '../../foo/bar'], + ['//foo/bar\\baz', '/foo/bar/baz'], + ['//foo\\bar\\baz', '/foo/bar/baz'], + ['/user/docs/Letter.txt', '/user/docs/Letter.txt'], + ['\\?\\C:\\user\\docs\\Letter.txt', '/?/C:/user/docs/Letter.txt'], + ['\\?\\UNC\\Server01\\user\\docs\\Letter.txt', '/?/UNC/Server01/user/docs/Letter.txt'], + ['\\\\.\\CdRomX', '//./CdRomX'], + ['\\\\.\\PhysicalDiskX', '//./PhysicalDiskX'], + ['\\\\?\\C:\\user\\docs\\Letter.txt', '//?/C:/user/docs/Letter.txt'], + ['\\\\?\\UNC\\Server01\\user\\docs\\Letter.txt', '//?/UNC/Server01/user/docs/Letter.txt'], + ['\\Server01\\user\\docs\\Letter.txt', '/Server01/user/docs/Letter.txt'], + ['C:\\user\\docs\\Letter.txt', 'C:/user/docs/Letter.txt'], + [ + 'C:\\user\\docs\\somefile.ext:alternate_stream_name', + 'C:/user/docs/somefile.ext:alternate_stream_name', + ], + ['C:Letter.txt', 'C:Letter.txt'], + ['E://foo//bar//baz', 'E:/foo/bar/baz'], + ['E://foo//bar//baz//', 'E:/foo/bar/baz'], + ['E://foo//bar//baz//////', 'E:/foo/bar/baz'], + ['E://foo/bar\\baz', 'E:/foo/bar/baz'], + ['E://foo\\bar\\baz', 'E:/foo/bar/baz'], + ['E:/foo/bar/baz/', 'E:/foo/bar/baz'], + ['E:/foo/bar/baz///', 'E:/foo/bar/baz'], + ['E:\\\\foo/bar\\baz', 'E:/foo/bar/baz'], + ['foo\\bar\\baz', 'foo/bar/baz'], + ['foo\\bar\\baz\\', 'foo/bar/baz'], + ['foo\\bar\\baz\\\\\\', 'foo/bar/baz'], + ])('should normalize %s', (input, output) => { + expect(normalizePath(input)).toEqual(output) + }) + }) +}) diff --git a/test/unit/resolveGitRepo.spec.js b/test/unit/resolveGitRepo.spec.js index b98dcc093..ecee89c26 100644 --- a/test/unit/resolveGitRepo.spec.js +++ b/test/unit/resolveGitRepo.spec.js @@ -1,7 +1,6 @@ import path from 'node:path' -import normalize from 'normalize-path' - +import { normalizePath } from '../../lib/normalizePath.js' import { determineGitDir, resolveGitRepo } from '../../lib/resolveGitRepo.js' /** @@ -11,12 +10,12 @@ jest.unmock('execa') describe('resolveGitRepo', () => { it('should resolve to current working dir when .git is in the same dir', async () => { - const cwd = normalize(process.cwd()) + const cwd = normalizePath(process.cwd()) const { gitDir } = await resolveGitRepo() expect(gitDir).toEqual(cwd) }) - const expected = normalize(path.join(path.dirname(__dirname), '../')) + const expected = normalizePath(path.join(path.dirname(__dirname), '../')) it('should resolve to the parent dir when .git is in the parent dir', async () => { const processCwdBkp = process.cwd @@ -54,21 +53,21 @@ describe('resolveGitRepo', () => { const cwd = process.cwd() const relativeDir = undefined const rootDir = determineGitDir(cwd, relativeDir) - expect(rootDir).toEqual(normalize(cwd)) + expect(rootDir).toEqual(normalizePath(cwd)) }) it('should resolve to parent dir when relative dir is child', () => { const relativeDir = 'bar' const cwd = process.cwd() + path.sep + 'bar' const rootDir = determineGitDir(cwd, relativeDir) - expect(rootDir).toEqual(normalize(process.cwd())) + expect(rootDir).toEqual(normalizePath(process.cwd())) }) it('should resolve to parent dir when relative dir is child and child has trailing dir separator', () => { const relativeDir = 'bar' + path.sep const cwd = process.cwd() + path.sep + 'bar' const rootDir = determineGitDir(cwd, relativeDir) - expect(rootDir).toEqual(normalize(process.cwd())) + expect(rootDir).toEqual(normalizePath(process.cwd())) }) }) }) diff --git a/test/unit/runAll.spec.js b/test/unit/runAll.spec.js index 414d8161f..d96b3eeb1 100644 --- a/test/unit/runAll.spec.js +++ b/test/unit/runAll.spec.js @@ -2,14 +2,14 @@ import path from 'node:path' import makeConsoleMock from 'consolemock' import { execa } from 'execa' -import normalize from 'normalize-path' import { getStagedFiles } from '../../lib/getStagedFiles.js' import { GitWorkflow } from '../../lib/gitWorkflow.js' +import { normalizePath } from '../../lib/normalizePath.js' import { resolveGitRepo } from '../../lib/resolveGitRepo.js' import { runAll } from '../../lib/runAll.js' -import { ConfigNotFoundError, GitError } from '../../lib/symbols.js' import * as searchConfigsNS from '../../lib/searchConfigs.js' +import { ConfigNotFoundError, GitError } from '../../lib/symbols.js' import { mockExecaReturnValue } from './__utils__/mockExecaReturnValue.js' @@ -39,7 +39,7 @@ getStagedFiles.mockImplementation(async () => []) resolveGitRepo.mockImplementation(async () => { const cwd = process.cwd() - return { gitConfigDir: normalize(path.resolve(cwd, '.git')), gitDir: normalize(cwd) } + return { gitConfigDir: normalizePath(path.resolve(cwd, '.git')), gitDir: normalizePath(cwd) } }) const configPath = '.lintstagedrc.json' @@ -260,7 +260,7 @@ describe('runAll', () => { expect(mockTask).toHaveBeenCalledWith(['foo.js']) // GitWorkflow received absolute `test/foo.js` expect(mockConstructor).toHaveBeenCalledTimes(1) - expect(expected).toEqual([[normalize(path.join(cwd, 'test/foo.js'))]]) + expect(expected).toEqual([[normalizePath(path.join(cwd, 'test/foo.js'))]]) }) it('should resolve matched files to config locations with multiple configs', async () => { @@ -288,8 +288,8 @@ describe('runAll', () => { expect(mockConstructor).toHaveBeenCalledTimes(1) expect(expected).toEqual([ [ - normalize(path.join(process.cwd(), 'test/foo.js')), - normalize(path.join(process.cwd(), 'foo.js')), + normalizePath(path.join(process.cwd(), 'test/foo.js')), + normalizePath(path.join(process.cwd(), 'foo.js')), ], ]) }) diff --git a/test/unit/searchConfigs.spec.js b/test/unit/searchConfigs.spec.js index 9d0a2ac8e..9739e62b2 100644 --- a/test/unit/searchConfigs.spec.js +++ b/test/unit/searchConfigs.spec.js @@ -1,9 +1,8 @@ import path from 'node:path' -import normalize from 'normalize-path' - import { execGit } from '../../lib/execGit.js' import { loadConfig } from '../../lib/loadConfig.js' +import { normalizePath } from '../../lib/normalizePath.js' import { searchConfigs } from '../../lib/searchConfigs.js' jest.mock('../../lib/resolveConfig', () => ({ @@ -79,7 +78,7 @@ describe('searchConfigs', () => { it('should return config found from git', async () => { const configFile = '.lintstagedrc.json' - const configPath = normalize(path.join(process.cwd(), configFile)) + const configPath = normalizePath(path.join(process.cwd(), configFile)) const config = { '*.js': 'eslint' } execGit.mockResolvedValueOnce(`${configFile}\u0000`) @@ -89,7 +88,7 @@ describe('searchConfigs', () => { }) it('should return auto-discovered config from cwd when not found from git', async () => { - const configPath = normalize(path.join(process.cwd(), '.lintstagedrc.json')) + const configPath = normalizePath(path.join(process.cwd(), '.lintstagedrc.json')) const config = { '*.js': 'eslint' } loadConfig.mockResolvedValueOnce({ config, filepath: configPath }) @@ -104,9 +103,11 @@ describe('searchConfigs', () => { `.lintstagedrc.json\u0000even/deeper/.lintstagedrc.json\u0000deeper/.lintstagedrc.json\u0000` ) - const topLevelConfig = normalize(path.join(process.cwd(), '.lintstagedrc.json')) - const deeperConfig = normalize(path.join(process.cwd(), 'deeper/.lintstagedrc.json')) - const evenDeeperConfig = normalize(path.join(process.cwd(), 'even/deeper/.lintstagedrc.json')) + const topLevelConfig = normalizePath(path.join(process.cwd(), '.lintstagedrc.json')) + const deeperConfig = normalizePath(path.join(process.cwd(), 'deeper/.lintstagedrc.json')) + const evenDeeperConfig = normalizePath( + path.join(process.cwd(), 'even/deeper/.lintstagedrc.json') + ) loadConfig.mockResolvedValueOnce({ config, filepath: topLevelConfig }) loadConfig.mockResolvedValueOnce({ config, filepath: deeperConfig })