Skip to content

refactor: replace find-up with escalade#4605

Merged
escapedcat merged 3 commits intoconventional-changelog:masterfrom
hyperz111:escalade
Jan 27, 2026
Merged

refactor: replace find-up with escalade#4605
escapedcat merged 3 commits intoconventional-changelog:masterfrom
hyperz111:escalade

Conversation

@hyperz111
Copy link
Contributor

@hyperz111 hyperz111 commented Jan 25, 2026

User description

Description

Replace find-up with escalade.

Motivation and Context

find-up is has 5 dependencies in its tree but escalade is has 0 dependencies in its tree.
And because yargs use it, we maybe don't add the dependency :).

Usage examples

How Has This Been Tested?

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

PR Type

Enhancement


Description

  • Replace find-up dependency with escalade

  • Reduce dependency tree from 5 to 0 dependencies

  • Simplify git root detection logic

  • Leverage existing yargs dependency


Diagram Walkthrough

flowchart LR
  A["find-up<br/>5 dependencies"] -->|replace| B["escalade<br/>0 dependencies"]
  B -->|simplify| C["Git root detection"]
  D["yargs<br/>already uses escalade"] -.->|reuse| B
Loading

File Walkthrough

Relevant files
Enhancement
index.ts
Refactor git root detection with escalade                               

@commitlint/top-level/src/index.ts

  • Replace find-up import with escalade
  • Add process import for default cwd
  • Refactor toplevel() to use escalade directly
  • Remove separate searchDotGit() helper function
  • Simplify logic to check for .git in directory files
+8/-22   
Dependencies
package.json
Update dependencies find-up to escalade                                   

@commitlint/top-level/package.json

  • Remove find-up dependency version ^7.0.0
  • Add escalade dependency version ^3.2.0
+1/-1     

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 25, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jan 25, 2026

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 25, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Remove unnecessary async/await
Suggestion Impact:The toplevel function was changed from async/await to a normal function that directly returns the promise from escalade.

code diff:

-export default async function toplevel(cwd = process.cwd()) {
-	return await escalade(cwd, (directory, files) => {
+export default function toplevel(cwd = process.cwd()) {
+	return escalade(cwd, (directory, files) => {

Remove the unnecessary async/await from the toplevel function by returning the
promise from escalade directly.

@commitlint/top-level/src/index.ts [7-13]

-export default async function toplevel(cwd = process.cwd()) {
-	return await escalade(cwd, (directory, files) => {
+export default function toplevel(cwd = process.cwd()) {
+	return escalade(cwd, (directory, files) => {
 		if (files.includes(".git")) {
 			return directory;
 		}
 	});
 }

[Suggestion processed]

Suggestion importance[1-10]: 4

__

Why: This is a valid suggestion that simplifies the code by removing a redundant async/await, which is a good practice for cleaner code. The impact is minor, improving readability and avoiding an unnecessary microtask.

Low
  • Update

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Replaces find-up with escalade for locating the nearest Git root in @commitlint/top-level, aiming to reduce the dependency footprint.

Changes:

  • Refactor Git root discovery to use escalade instead of find-up.
  • Update @commitlint/top-level dependencies to remove find-up and add escalade.
  • Remove now-unused find-up@^7-related entries from yarn.lock.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
@commitlint/top-level/src/index.ts Switches Git root detection implementation from find-up to escalade.
@commitlint/top-level/package.json Replaces runtime dependency find-up with escalade.
yarn.lock Drops lock entries that were only needed for find-up@^7.0.0 and its dependency chain.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@escapedcat
Copy link
Member

Great idea! Thanks!

Got this AI feedback:


PR Review Summary

Thanks for this PR! The dependency reduction is a great improvement. However, there are a few items that need to be addressed before merging:

✅ What's Good

  • Excellent dependency reduction: Removes 6 packages from the tree (find-up + 5 transitive deps)
  • No new dependencies: escalade is already present via yargs
  • Smaller bundle size: escalade is only ~183-210 bytes
  • Code simplification: Reduces from 28 to 13 lines

❌ Required Changes

  1. Remove unnecessary async/await (Code Style)
    The async/await keywords are redundant since you're just passing through the promise:
    -export default async function toplevel(cwd = process.cwd()) {
    • return await escalade(cwd, (directory, files) => {
      +export default function toplevel(cwd = process.cwd()) {
    • return escalade(cwd, (directory, files) => {
      if (files.includes(".git")) {
      return directory;
      }
      });
      }
  2. Add Tests (CRITICAL - Currently Missing)
    There are currently no tests for @commitlint/top-level. Before merging, we need tests to verify:
    • ✅ Finding normal git repos (.git as directory)
    • ✅ Finding git submodules (.git as file)
    • ✅ Handling non-git directories (should return undefined)
    • ✅ Respecting the cwd parameter
    • ✅ Working from nested directories
      This is especially important because the original code explicitly handled .git as both a file (submodules) and directory (normal repos). We need to verify escalade handles both cases correctly.
  3. Manual Testing Verification
    Please confirm you've tested this change in:
    • A normal git repository
    • A git submodule (where .git is a file, not a directory)
    • A directory that's not in a git repo
    • Using commitlint CLI end-to-end

❓ Question

The original code explicitly checked for .git as both a file (submodules) and directory (normal repos). The escalade callback's files parameter includes both files and directories in its array. Can you confirm this works correctly for submodules where .git is a file pointing to the parent repo's modules directory?

Recommendation

Once tests are added and the async/await is fixed, this PR will be ready to merge. The dependency reduction is valuable and escalade is a solid choice!


After looking at this it might be better to first add tests to the module before we exchange the dep. wdyt?

@hyperz111
Copy link
Contributor Author

@escapedcat, what about this?

@escapedcat
Copy link
Member

After looking at this it might be better to first add tests to the module before we exchange the dep. wdyt?

Sorry, the main point here is to first add tests to the current master for top-level, let those pass and then make sure they still pass with this PR. Makes sense?

This comment was marked as off-topic.

@escapedcat
Copy link
Member

Thanks! Is it possible to include further test cases?:

Test Coverage Analysis:
The PR author added these 3 tests:

  1. ✅ Finding normal git repos (.git as directory)
  2. ✅ Finding git submodules (.git as file)
  3. ✅ Handling non-git directories (returns undefined)

However, from my original review requirements, these are missing:

  • ⚠️ Testing with explicit cwd parameter (partially covered, but not explicitly tested)
  • ⚠️ Testing from deeply nested directories (the tests use path.join(temp, "src", "shared") which is only 2 levels deep)

@hyperz111
Copy link
Contributor Author

hyperz111 commented Jan 27, 2026

  • ⚠️ Testing with explicit cwd parameter (partially covered, but not explicitly tested)

I have do it before.

  • ⚠️ Testing from deeply nested directories (the tests use path.join(temp, "src", "shared") which is only 2 levels deep)

I will try this.

@escapedcat
Copy link
Member

Thanks!

@escapedcat
Copy link
Member

Thanks! 👏

Now you can re-add the commits from before. Sorry for the confusion!

@escapedcat escapedcat merged commit 3d6b232 into conventional-changelog:master Jan 27, 2026
23 checks passed
@escapedcat
Copy link
Member

❤️

@hyperz111 hyperz111 mentioned this pull request Jan 27, 2026
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants