From 8d7a2829dd18c4fe26919d981a15d1bbcb6f8082 Mon Sep 17 00:00:00 2001 From: "Joseph D. Harvey" Date: Thu, 16 Nov 2023 23:42:42 -0500 Subject: [PATCH] fix: resolution of overlapping root and tracked file paths --- src/main/core/tracked-file-enumerator.ts | 36 +++++++++++++++++-- src/main/scopes/jsx/jsx-scope.ts | 8 ++--- src/main/scopes/npm/get-package-data.ts | 6 ++-- .../jsx/tracked-file-enumerator.test.ts | 2 +- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/main/core/tracked-file-enumerator.ts b/src/main/core/tracked-file-enumerator.ts index 368feb26..6a7fd282 100644 --- a/src/main/core/tracked-file-enumerator.ts +++ b/src/main/core/tracked-file-enumerator.ts @@ -6,6 +6,7 @@ */ import path from 'path' +import { InvalidRootPathError } from '../exceptions/invalid-root-path-error.js' import { Loggable } from './log/loggable.js' import { Trace } from './log/trace.js' import { runCommand } from './run-command.js' @@ -42,7 +43,38 @@ export class TrackedFileEnumerator extends Loggable { return allFiles .filter((_file, index) => checks[index] === true) - .map((file) => path.relative(root, file)) - .map((file) => path.resolve(root, file)) + .map((file) => this.findAbsolutePath(file, root)) + } + + /** + * Given two paths that have partially overlapping directory hierarchies, find an absolute path + * that uses as many pieces of the two paths as possible. + * + * @param trackedFile - A file obtained from a git ls-tree command. This is NOT an absolute path. + * @param root - An absolute path representing a root director in which the tracked file is + * contained. + * @throws InvalidRootPathError if no valid path could be constructed using parts from both the + * trackedFile path and the root path. + * @returns A path. + */ + private findAbsolutePath(trackedFile: string, root: string) { + trackedFile = path.normalize(trackedFile) + root = path.normalize(root) + const trackedFileParts = trackedFile.split(path.sep) + const suffixParts: string[] = [] + + while (trackedFileParts.length > 0) { + if (root.endsWith(trackedFileParts.join(path.sep))) { + break + } + + suffixParts.unshift(trackedFileParts.pop() ?? '') + } + + if (trackedFileParts.length === 0) { + throw new InvalidRootPathError(trackedFile, root) + } + + return path.join(root, ...suffixParts) } } diff --git a/src/main/scopes/jsx/jsx-scope.ts b/src/main/scopes/jsx/jsx-scope.ts index fd0af22c..709fe1fa 100644 --- a/src/main/scopes/jsx/jsx-scope.ts +++ b/src/main/scopes/jsx/jsx-scope.ts @@ -66,6 +66,7 @@ export class JsxScope extends Scope { const packageJsonTree = await getPackageJsonTree(this.root, this.logger) const instrumentedPackage = await getPackageData(this.cwd, this.logger) const sourceFiles = await getTrackedSourceFiles(this.root, this.logger) + const promises = sourceFiles.map(async (sourceFile) => { const accumulator = new JsxElementAccumulator() @@ -132,7 +133,6 @@ export class JsxScope extends Scope { * @param accumulator - Accumulator to store results in. * @param sourceFilePath - Absolute path to a sourceFile. * @param packageJsonTree - Directory tree of package.json files. - * @returns Promise of all invokers getting resolved. */ async resolveInvokers( accumulator: JsxElementAccumulator, @@ -149,12 +149,10 @@ export class JsxScope extends Scope { return } - const promises = accumulator.elements.map(async (jsxElement) => { - const containingPackageData = await getPackageData(containingDir, this.logger) + const containingPackageData = await getPackageData(containingDir, this.logger) + accumulator.elements.forEach((jsxElement) => { accumulator.elementInvokers.set(jsxElement, containingPackageData.name) }) - - await Promise.allSettled(promises) } } diff --git a/src/main/scopes/npm/get-package-data.ts b/src/main/scopes/npm/get-package-data.ts index c4744603..cca5e43e 100644 --- a/src/main/scopes/npm/get-package-data.ts +++ b/src/main/scopes/npm/get-package-data.ts @@ -23,8 +23,8 @@ export async function getPackageData(packagePath: string, logger: Logger): Promi const result = await runCommand('npm pkg get name version', logger, { cwd: packagePath }) - const parsed = JSON.parse(result.stdout) + const data = JSON.parse(result.stdout) - logger.traceExit('', 'getPackageData', parsed) - return parsed + logger.traceExit('', 'getPackageData', data) + return data } diff --git a/src/test/scopes/jsx/tracked-file-enumerator.test.ts b/src/test/scopes/jsx/tracked-file-enumerator.test.ts index 343d74b8..b7eca274 100644 --- a/src/test/scopes/jsx/tracked-file-enumerator.test.ts +++ b/src/test/scopes/jsx/tracked-file-enumerator.test.ts @@ -37,7 +37,7 @@ describe('class: TrackedFileEnumerator', () => { ).resolves.toHaveLength(0) }) - it('returns correctly resolved relative paths', async () => { + it('returns correctly resolved absolute paths', async () => { const root = new Fixture('projects/nested-project-files') const files = await enumerator.find(root.path, (fileName) => fileName.endsWith('.js'))