From 6676f55cd7387885f9c6671e34f9340492858b4c Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 31 Dec 2024 07:10:02 +0100 Subject: [PATCH] feat: add `stop` option to detect Currently we can't break the traversing up directories, which we now can. --- src/detect.ts | 12 ++++++++++-- src/types.ts | 4 ++++ test/detect-sync.spec.ts | 32 ++++++++++++++++++++++++++++++++ test/detect.spec.ts | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/detect.ts b/src/detect.ts index 3af1526..ade2bb9 100644 --- a/src/detect.ts +++ b/src/detect.ts @@ -11,7 +11,7 @@ import { AGENTS, LOCKS } from './constants' * @returns {Promise} The detected package manager or `null` if not found. */ export async function detect(options: DetectOptions = {}): Promise { - const { cwd, onUnknown } = options + const { cwd, onUnknown, stop } = options for (const directory of lookup(cwd)) { // Look up for lock files @@ -29,6 +29,10 @@ export async function detect(options: DetectOptions = {}): Promise} The detected package manager or `null` if not found. */ export function detectSync(options: DetectOptions = {}): DetectResult | null { - const { cwd, onUnknown } = options + const { cwd, onUnknown, stop } = options for (const directory of lookup(cwd)) { // Look up for lock files @@ -58,6 +62,10 @@ export function detectSync(options: DetectOptions = {}): DetectResult | null { const result = parsePackageJsonSync(path.join(directory, 'package.json'), onUnknown) if (result) return result + + // Stop the traversing if the stop directory is reached + if (stop && path.resolve(directory) === path.resolve(stop)) + break } return null diff --git a/src/types.ts b/src/types.ts index 71b88e7..8fc2132 100644 --- a/src/types.ts +++ b/src/types.ts @@ -42,6 +42,10 @@ export interface DetectOptions { * @param packageManager - The `packageManager` value from package.json file. */ onUnknown?: (packageManager: string) => DetectResult | null | undefined + /** + * The path to stop traversing up the directory. + */ + stop?: string } export interface DetectResult { diff --git a/test/detect-sync.spec.ts b/test/detect-sync.spec.ts index 7ea5596..a5a233b 100644 --- a/test/detect-sync.spec.ts +++ b/test/detect-sync.spec.ts @@ -42,3 +42,35 @@ fixtures.forEach(fixture => describe(fixture, () => agents.forEach((agent) => { expect(infoLog).not.toHaveBeenCalled() }) }))) + +it('stops at specified directory', async () => { + const cwd = await fs.mkdtemp(path.join(tmpdir(), 'ni-')) + + const noFilesDir = path.join(cwd, 'no-files') + const nestedNoFilesDir = path.join(noFilesDir, 'nested') + const parentDir = cwd + + await fs.mkdirp(noFilesDir) + await fs.mkdirp(nestedNoFilesDir) + + await fs.copy( + path.join(__dirname, 'fixtures', 'lockfile', 'npm'), + parentDir, + ) + + const resultWithStop = detectSync({ + cwd: nestedNoFilesDir, + stop: noFilesDir, + }) + + expect(resultWithStop).toBe(null) + + const resultWithoutStop = detectSync({ + cwd: nestedNoFilesDir, + }) + + expect(resultWithoutStop).toMatchObject({ + name: 'npm', + agent: 'npm', + }) +}) diff --git a/test/detect.spec.ts b/test/detect.spec.ts index 2be821e..7b2f3ef 100644 --- a/test/detect.spec.ts +++ b/test/detect.spec.ts @@ -42,3 +42,35 @@ fixtures.forEach(fixture => describe(fixture, () => agents.forEach((agent) => { expect(infoLog).not.toHaveBeenCalled() }) }))) + +it('stops at specified directory', async () => { + const cwd = await fs.mkdtemp(path.join(tmpdir(), 'ni-')) + + const noFilesDir = path.join(cwd, 'no-files') + const nestedNoFilesDir = path.join(noFilesDir, 'nested') + const parentDir = cwd + + await fs.mkdirp(noFilesDir) + await fs.mkdirp(nestedNoFilesDir) + + await fs.copy( + path.join(__dirname, 'fixtures', 'lockfile', 'npm'), + parentDir, + ) + + const resultWithStop = await detect({ + cwd: nestedNoFilesDir, + stop: noFilesDir, + }) + + expect(resultWithStop).toBe(null) + + const resultWithoutStop = await detect({ + cwd: nestedNoFilesDir, + }) + + expect(resultWithoutStop).toMatchObject({ + name: 'npm', + agent: 'npm', + }) +})