diff --git a/libs/core/src/assets.spec.ts b/libs/core/src/assets.spec.ts index 80906f3..cc9461d 100644 --- a/libs/core/src/assets.spec.ts +++ b/libs/core/src/assets.spec.ts @@ -13,7 +13,7 @@ describe('findNonSourceAffectedFiles', () => { it('should return relevant files', () => { const cwd = '/project'; - const changedFilePath = '/project/src/file.ts'; + const changedFilePaths = ['/project/src/file.ts']; const excludeFolderPaths = ['node_modules', 'dist', '.git']; (fastFindInFiles as jest.Mock).mockReturnValue([ @@ -26,14 +26,50 @@ describe('findNonSourceAffectedFiles', () => { const result = findNonSourceAffectedFiles( cwd, - changedFilePath, + changedFilePaths, excludeFolderPaths ); expect(result).toEqual([{ filePath: 'src/file.ts', changedLines: [1] }]); expect(fastFindInFiles).toHaveBeenCalledWith({ directory: cwd, - needle: path.basename(changedFilePath), + needle: new RegExp( + changedFilePaths + .map((changedFilePath) => path.basename(changedFilePath)) + .join('|') + .replaceAll('.', '\\.') + ), + excludeFolderPaths: excludeFolderPaths.map((folder) => + path.join(cwd, folder) + ), + }); + }); + + it('should aggregate changedFilePaths to regExp needle', () => { + const cwd = '/project'; + const changedFilePaths = ['/project/src/file.ts', '/project/src/file2.ts']; + const excludeFolderPaths = ['node_modules', 'dist', '.git']; + (fastFindInFiles as jest.Mock).mockReturnValue([ + { + filePath: '/project/src/file.ts', + queryHits: [{ lineNumber: 1, line: `"file.ts"` }], + }, + ]); + (existsSync as jest.Mock).mockReturnValue(true); + const result = findNonSourceAffectedFiles( + cwd, + changedFilePaths, + excludeFolderPaths + ); + expect(result).toEqual([{ filePath: 'src/file.ts', changedLines: [1] }]); + expect(fastFindInFiles).toHaveBeenCalledWith({ + directory: cwd, + needle: new RegExp( + changedFilePaths + .map((changedFilePath) => path.basename(changedFilePath)) + .join('|') + .replaceAll('.', '\\.') + ), excludeFolderPaths: excludeFolderPaths.map((folder) => path.join(cwd, folder) ), @@ -42,7 +78,7 @@ describe('findNonSourceAffectedFiles', () => { it('should return empty array if no relevant files found', () => { const cwd = '/project'; - const changedFilePath = '/project/src/file.ts'; + const changedFilePaths = ['/project/src/file.ts']; const excludeFolderPaths = ['node_modules', 'dist', '.git']; (fastFindInFiles as jest.Mock).mockReturnValue([]); @@ -50,14 +86,19 @@ describe('findNonSourceAffectedFiles', () => { const result = findNonSourceAffectedFiles( cwd, - changedFilePath, + changedFilePaths, excludeFolderPaths ); expect(result).toEqual([]); expect(fastFindInFiles).toHaveBeenCalledWith({ directory: cwd, - needle: path.basename(changedFilePath), + needle: new RegExp( + changedFilePaths + .map((changedFilePath) => path.basename(changedFilePath)) + .join('|') + .replaceAll('.', '\\.') + ), excludeFolderPaths: excludeFolderPaths.map((folder) => path.join(cwd, folder) ), @@ -66,7 +107,7 @@ describe('findNonSourceAffectedFiles', () => { it("should still work even if found file didn't have a match", () => { const cwd = '/project'; - const changedFilePath = '/project/src/file.ts'; + const changedFilePaths = ['/project/src/file.ts']; const excludeFolderPaths = ['node_modules', 'dist', '.git']; (fastFindInFiles as jest.Mock).mockReturnValue([ @@ -79,14 +120,19 @@ describe('findNonSourceAffectedFiles', () => { const result = findNonSourceAffectedFiles( cwd, - changedFilePath, + changedFilePaths, excludeFolderPaths ); expect(result).toEqual([]); expect(fastFindInFiles).toHaveBeenCalledWith({ directory: cwd, - needle: path.basename(changedFilePath), + needle: new RegExp( + changedFilePaths + .map((changedFilePath) => path.basename(changedFilePath)) + .join('|') + .replaceAll('.', '\\.') + ), excludeFolderPaths: excludeFolderPaths.map((folder) => path.join(cwd, folder) ), diff --git a/libs/core/src/assets.ts b/libs/core/src/assets.ts index e0137ee..b8fb775 100644 --- a/libs/core/src/assets.ts +++ b/libs/core/src/assets.ts @@ -5,20 +5,22 @@ import { existsSync } from 'fs'; export function findNonSourceAffectedFiles( cwd: string, - changedFilePath: string, + changedFilePaths: string[], excludeFolderPaths: (string | RegExp)[] ): ChangedFiles[] { - const fileName = basename(changedFilePath); + if (changedFilePaths.length === 0) return []; + + const fileNames = changedFilePaths.map((path) => basename(path)); const files = fastFindInFiles({ directory: cwd, - needle: fileName, + needle: new RegExp(fileNames.join('|').replaceAll('.', '\\.')), excludeFolderPaths: excludeFolderPaths.map((path) => typeof path === 'string' ? join(cwd, path) : path ), }); - const relevantFiles = filterRelevantFiles(cwd, files, changedFilePath); + const relevantFiles = filterRelevantFiles(cwd, files, changedFilePaths); return relevantFiles; } @@ -26,21 +28,23 @@ export function findNonSourceAffectedFiles( function filterRelevantFiles( cwd: string, files: FastFindInFiles[], - changedFilePath: string + changedFilePaths: string[] ): ChangedFiles[] { - const fileName = basename(changedFilePath); - const regExp = new RegExp(`['"\`](?.*${fileName})['"\`]`); + return changedFilePaths.flatMap((changedFilePath) => { + const fileName = basename(changedFilePath); + const regExp = new RegExp(`['"\`](?.*${fileName})['"\`]`); - return files - .map(({ filePath: foundFilePath, queryHits }) => ({ - filePath: relative(cwd, foundFilePath), - changedLines: queryHits - .filter(({ line }) => - isRelevantLine(line, regExp, cwd, foundFilePath, changedFilePath) - ) - .map(({ lineNumber }) => lineNumber), - })) - .filter(({ changedLines }) => changedLines.length > 0); + return files + .map(({ filePath: foundFilePath, queryHits }) => ({ + filePath: relative(cwd, foundFilePath), + changedLines: queryHits + .filter(({ line }) => + isRelevantLine(line, regExp, cwd, foundFilePath, changedFilePath) + ) + .map(({ lineNumber }) => lineNumber), + })) + .filter(({ changedLines }) => changedLines.length > 0); + }); } function isRelevantLine( diff --git a/libs/core/src/true-affected.ts b/libs/core/src/true-affected.ts index aa0e06d..5f9be8e 100644 --- a/libs/core/src/true-affected.ts +++ b/libs/core/src/true-affected.ts @@ -99,20 +99,28 @@ export const trueAffected = async ({ ({ filePath }) => project.getSourceFile(resolve(cwd, filePath)) != null ); - const nonSourceChangedFiles = changedFiles + const nonSourceChangedFilesPaths = changedFiles .filter( ({ filePath }) => !filePath.match(/.*\.(ts|js)x?$/g) && !filePath.endsWith(lockFileName) && project.getSourceFile(resolve(cwd, filePath)) == null ) - .flatMap(({ filePath: changedFilePath }) => { - logger.debug( - `Finding non-source affected files for ${chalk.bold(changedFilePath)}` - ); + .map(({ filePath }) => filePath); - return findNonSourceAffectedFiles(cwd, changedFilePath, ignoredPaths); - }); + if (nonSourceChangedFilesPaths.length > 0) { + logger.debug( + `Finding non-source affected files for ${chalk.bold( + nonSourceChangedFilesPaths.join(', ') + )}` + ); + } + + const nonSourceChangedFiles = findNonSourceAffectedFiles( + cwd, + nonSourceChangedFilesPaths, + ignoredPaths + ); if (nonSourceChangedFiles.length > 0) { logger.debug( diff --git a/tsconfig.base.json b/tsconfig.base.json index 7b786af..112e137 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -10,7 +10,7 @@ "importHelpers": true, "target": "es2015", "module": "esnext", - "lib": ["es2020", "dom"], + "lib": ["es2023", "dom"], "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".",