From b2477789324ebc82b7cd3b83495c60d1dbffcb99 Mon Sep 17 00:00:00 2001 From: racgoo Date: Sun, 28 Dec 2025 18:57:03 +0900 Subject: [PATCH 01/11] feat: add worktree feature --- index.d.ts | 304 ++++++++++++++++++++++++++++-- index.js | 1 + src/lib.rs | 1 + src/repository.rs | 16 -- src/worktree.rs | 414 +++++++++++++++++++++++++++++++++++++++++ tests/worktree.spec.ts | 0 6 files changed, 706 insertions(+), 30 deletions(-) create mode 100644 src/worktree.rs create mode 100644 tests/worktree.spec.ts diff --git a/index.d.ts b/index.d.ts index 01cfca2..fb4fe95 100644 --- a/index.d.ts +++ b/index.d.ts @@ -4126,20 +4126,6 @@ export declare class Repository { * @returns Returns `true` if repository is a shallow clone. */ isShallow(): boolean - /** - * Tests whether this repository is a worktree. - * - * @category Repository/Methods - * @signature - * ```ts - * class Repository { - * isWorktree(): boolean; - * } - * ``` - * - * @returns Returns `true` if repository is a worktree. - */ - isWorktree(): boolean /** * Tests whether this repository is empty. * @@ -5171,6 +5157,89 @@ export declare class Repository { * @returns If it does not exist, returns `null`. */ findTree(oid: string): Tree | null + /** + * Add a new worktree to the repository. + * + * @category Repository/Methods + * + * @signature + * ```ts + * class Repository { + * worktree(name: string, path: string, options?: WorktreeAddOptions | null | undefined): Worktree; + * } + * ``` + * + * @param {string} name - Name of the worktree to add. + * @param {string} path - Path where the worktree should be created. + * @param {WorktreeAddOptions} [options] - Options for adding the worktree. + * @returns New worktree instance. + * @throws Throws error if adding the worktree fails. + */ + worktree(name: string, path: string, options?: WorktreeAddOptions | undefined | null): Worktree + /** + * List all worktrees in the repository. + * + * @category Repository/Methods + * + * @signature + * ```ts + * class Repository { + * worktrees(): string[]; + * } + * ``` + * + * @returns Array of worktree names. + * @throws Throws error if listing worktrees fails. + */ + worktrees(): Array + /** + * Tests whether this repository is a worktree. + * + * @category Repository/Methods + * @signature + * ```ts + * class Repository { + * isWorktree(): boolean; + * } + * ``` + * + * @returns Returns `true` if repository is a worktree. + */ + isWorktree(): boolean + /** + * Find a worktree by name. + * + * @category Repository/Methods + * + * @signature + * ```ts + * class Repository { + * findWorktree(name: string): Worktree; + * } + * ``` + * + * @param {string} name - Name of the worktree to find. + * @returns Worktree instance. + * @throws Throws error if the worktree is not found or if opening fails. + */ + findWorktree(name: string): Worktree + /** + * Open a repository from a worktree. + * + * @category Repository/Methods + * + * @signature + * ```ts + * class Repository { + * static openFromWorktree(worktree: Worktree): Repository; + * } + * ``` + * + * @param {Worktree} worktree - Worktree to open repository from. + * @returns Repository instance. + * @throws Throws error if opening the repository fails. + */ + static openFromWorktree(worktree: Worktree): Repository } /** @@ -6437,6 +6506,152 @@ export declare class TreeIter extends Iterator { next(value?: void): IteratorResult } +/** A class to represent a git worktree. */ +export declare class Worktree { + /** + * Open a worktree from a repository. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * static openFromRepository(repo: Repository): Worktree; + * } + * ``` + * + * @param {Repository} repo - Repository to open worktree from. + * @returns Worktree instance. + * @throws Throws error if the repository is not a worktree or if opening fails. + */ + static openFromRepository(repo: Repository): Worktree + /** + * Get the name of this worktree. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * name(): string | null; + * } + * ``` + * + * @returns Name of this worktree. Returns `null` if the worktree has no name. + */ + name(): string | null + /** + * Get the path of this worktree. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * path(): string; + * } + * ``` + * + * @returns Path of this worktree. + */ + path(): string + /** + * Validate that the worktree is in a valid state. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * validate(): void; + * } + * ``` + * + * @throws Throws error if the worktree is in an invalid state. + */ + validate(): void + /** + * Lock the worktree. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * lock(reason?: string | null | undefined): void; + * } + * ``` + * + * @param {string} [reason] - Optional reason for locking the worktree. + * @throws Throws error if locking fails. + */ + lock(reason?: string | undefined | null): void + /** + * Unlock the worktree. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * unlock(): void; + * } + * ``` + * + * @throws Throws error if unlocking fails. + */ + unlock(): void + /** + * Check if the worktree is locked. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * isLocked(): WorktreeLockStatus; + * } + * ``` + * + * @returns Lock status of the worktree. + * @throws Throws error if checking the lock status fails. + */ + isLocked(): WorktreeLockStatus + /** + * Prune the worktree. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * prune(options?: WorktreePruneOptions | null | undefined): void; + * } + * ``` + * + * @param {WorktreePruneOptions} [options] - Options for pruning the worktree. + * @throws Throws error if pruning fails. + */ + prune(worktreePruneOptions?: WorktreePruneOptions | undefined | null): void + /** + * Check if the worktree is prunable. + * + * @category Worktree/Methods + * + * @signature + * ```ts + * class Worktree { + * isPrunable(options?: WorktreePruneOptions | null | undefined): boolean; + * } + * ``` + * + * @param {WorktreePruneOptions} [options] - Options for checking if the worktree is prunable. + * @returns `true` if the worktree is prunable, `false` otherwise. + * @throws Throws error if checking fails. + */ + isPrunable(worktreePruneOptions?: WorktreePruneOptions | undefined | null): boolean +} + export interface AddMailmapEntryData { realName?: string realEmail?: string @@ -8983,6 +9198,67 @@ export declare function traceSet(level: TraceLevel, callback: (level: TraceLevel export type TreeWalkMode = 'PreOrder'| 'PostOrder'; +/** Options for adding a worktree. */ +export interface WorktreeAddOptions { + /** + * If enabled, this will cause the newly added worktree to be locked. + * + * Locking prevents the worktree from being pruned or deleted inadvertently. + * This is useful for worktrees stored on removable devices or network shares + * that may not always be accessible. + * + * Defaults to `false`. + */ + lock?: boolean + /** + * If enabled, this will checkout the existing branch matching the worktree name. + * + * When creating a worktree, if a branch with the same name as the worktree + * already exists, this option allows checking out that branch instead of + * creating a new one. + * + * Defaults to `false`. + */ + checkoutExisting?: boolean + /** + * Reference to use for the new worktree HEAD. + * + * This should be a reference name (e.g., `"refs/heads/main"`). If not provided, + * the worktree will checkout the branch that HEAD currently points to in the + * main repository. + * + * Defaults to `null`. + */ + refName?: string +} + +/** Lock Status of a worktree */ +export type WorktreeLockStatus = + | { type: 'Unlocked' } + | { type: 'Locked', field0?: string } + +/** Options to configure how worktree pruning is performed. */ +export interface WorktreePruneOptions { + /** + * Controls whether valid (still existing on the filesystem) worktrees will be pruned. + * + * Defaults to `false`. + */ + valid?: boolean + /** + * Controls whether locked worktrees will be pruned. + * + * Defaults to `false`. + */ + locked?: boolean + /** + * Controls whether the actual working tree on the filesystem is recursively removed. + * + * Defaults to `false`. + */ + workingTree?: boolean +} + /** * Creates an all zero Oid structure. * diff --git a/index.js b/index.js index 61e2712..3e8415e 100644 --- a/index.js +++ b/index.js @@ -613,6 +613,7 @@ module.exports.Tag = nativeBinding.Tag module.exports.Tree = nativeBinding.Tree module.exports.TreeEntry = nativeBinding.TreeEntry module.exports.TreeIter = nativeBinding.TreeIter +module.exports.Worktree = nativeBinding.Worktree module.exports.ApplyLocation = nativeBinding.ApplyLocation module.exports.AutotagOption = nativeBinding.AutotagOption module.exports.BranchType = nativeBinding.BranchType diff --git a/src/lib.rs b/src/lib.rs index 6540597..5ccbcbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub mod tag; pub mod tracing; pub mod tree; pub(crate) mod util; +pub mod worktree; pub use error::Error; pub type Result = std::result::Result; diff --git a/src/repository.rs b/src/repository.rs index 9160bc2..a96f429 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -278,22 +278,6 @@ impl Repository { self.inner.is_shallow() } - #[napi] - /// Tests whether this repository is a worktree. - /// - /// @category Repository/Methods - /// @signature - /// ```ts - /// class Repository { - /// isWorktree(): boolean; - /// } - /// ``` - /// - /// @returns Returns `true` if repository is a worktree. - pub fn is_worktree(&self) -> bool { - self.inner.is_worktree() - } - #[napi] /// Tests whether this repository is empty. /// diff --git a/src/worktree.rs b/src/worktree.rs new file mode 100644 index 0000000..bc31544 --- /dev/null +++ b/src/worktree.rs @@ -0,0 +1,414 @@ +use crate::repository::Repository; +use crate::util::path_to_string; +use napi::bindgen_prelude::{Reference, SharedReference}; +use napi::Env; +use napi_derive::napi; +use std::ops::Deref; +use std::path::Path; + +#[napi(string_enum)] +/// Lock Status of a worktree +pub enum WorktreeLockStatus { + /// Worktree is Unlocked + Unlocked, + /// Worktree is locked with the optional message + Locked(Option), +} + +#[napi(object)] +/// Options for adding a worktree. +pub struct WorktreeAddOptions { + /// If enabled, this will cause the newly added worktree to be locked. + /// Defaults to `false`. + pub lock: Option, + + /// If enabled, this will checkout the existing branch matching the worktree name. + /// Defaults to `false`. + pub checkout_existing: Option, + + /// reference name to use for the new worktree HEAD + /// Defaults to `null`. + pub ref_name: Option, +} + +#[napi(object)] +/// Options to configure how worktree pruning is performed. +pub struct WorktreePruneOptions { + /// Controls whether valid (still existing on the filesystem) worktrees will be pruned. + /// Defaults to `false`. + pub valid: Option, + + /// Controls whether locked worktrees will be pruned. + /// Defaults to `false`. + pub locked: Option, + + /// Controls whether the actual working tree on the filesystem is recursively removed. + /// Defaults to `false`. + pub working_tree: Option, +} + +impl From for git2::WorktreePruneOptions { + fn from(value: WorktreePruneOptions) -> Self { + let mut git2_worktree_prune_options = git2::WorktreePruneOptions::new(); + value.valid.map(|_valid| git2_worktree_prune_options.valid(_valid)); + value.valid.map(|_locked| git2_worktree_prune_options.locked(_locked)); + value + .valid + .map(|_working_tree| git2_worktree_prune_options.working_tree(_working_tree)); + git2_worktree_prune_options + } +} + +impl From for WorktreeLockStatus { + fn from(value: git2::WorktreeLockStatus) -> Self { + match value { + git2::WorktreeLockStatus::Unlocked => WorktreeLockStatus::Unlocked, + git2::WorktreeLockStatus::Locked(reason) => WorktreeLockStatus::Locked(reason), + } + } +} + +pub(crate) enum WorktreeInner { + Repo(SharedReference), +} + +impl Deref for WorktreeInner { + type Target = git2::Worktree; + + fn deref(&self) -> &Self::Target { + match self { + Self::Repo(inner) => inner.deref(), + } + } +} + +#[napi] +/// A class to represent a git worktree. +pub struct Worktree { + pub(crate) inner: WorktreeInner, +} + +#[napi] +impl Worktree { + #[napi] + /// Open a worktree from a repository. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// static openFromRepository(repo: Repository): Worktree; + /// } + /// ``` + /// + /// @param {Repository} repo - Repository to open worktree from. + /// @returns Worktree instance. + /// @throws Throws error if the repository is not a worktree or if opening fails. + pub fn open_from_repository(repo: Reference, env: Env) -> crate::Result { + let worktree = repo.share_with(env, |repo| { + git2::Worktree::open_from_repository(&repo.inner) + .map_err(crate::Error::from) + .map_err(|e| e.into()) + })?; + Ok(Worktree { + inner: WorktreeInner::Repo(worktree), + }) + } + + #[napi] + /// Get the name of this worktree. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// name(): string | null; + /// } + /// ``` + /// + /// @returns Name of this worktree. Returns `null` if the worktree has no name. + pub fn name(&self) -> Option { + self.inner.name().map(String::from) + } + + #[napi] + /// Get the path of this worktree. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// path(): string; + /// } + /// ``` + /// + /// @returns Path of this worktree. + pub fn path(&self) -> String { + path_to_string(self.inner.path()) + } + + #[napi] + /// Validate that the worktree is in a valid state. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// validate(): void; + /// } + /// ``` + /// + /// @throws Throws error if the worktree is in an invalid state. + pub fn validate(&self) -> crate::Result<()> { + self.inner.validate().map_err(crate::Error::from) + } + + #[napi] + /// Lock the worktree. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// lock(reason?: string | null | undefined): void; + /// } + /// ``` + /// + /// @param {string} [reason] - Optional reason for locking the worktree. + /// @throws Throws error if locking fails. + pub fn lock(&self, reason: Option) -> crate::Result<()> { + self.inner.lock(reason.as_deref()).map_err(crate::Error::from) + } + + #[napi] + /// Unlock the worktree. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// unlock(): void; + /// } + /// ``` + /// + /// @throws Throws error if unlocking fails. + pub fn unlock(&self) -> crate::Result<()> { + self.inner.unlock().map_err(crate::Error::from) + } + + #[napi] + /// Check if the worktree is locked. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// isLocked(): WorktreeLockStatus; + /// } + /// ``` + /// + /// @returns Lock status of the worktree. + /// @throws Throws error if checking the lock status fails. + pub fn is_locked(&self) -> crate::Result { + let git2_lock_status = self.inner.is_locked()?; + Ok(git2_lock_status.into()) + } + + #[napi] + /// Prune the worktree. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// prune(options?: WorktreePruneOptions | null | undefined): void; + /// } + /// ``` + /// + /// @param {WorktreePruneOptions} [options] - Options for pruning the worktree. + /// @throws Throws error if pruning fails. + pub fn prune(&self, worktree_prune_options: Option) -> crate::Result<()> { + let mut git2_worktree_prune_options = worktree_prune_options.map(git2::WorktreePruneOptions::from); + self + .inner + .prune(git2_worktree_prune_options.as_mut()) + .map_err(crate::Error::from) + } + + #[napi] + /// Check if the worktree is prunable. + /// + /// @category Worktree/Methods + /// + /// @signature + /// ```ts + /// class Worktree { + /// isPrunable(options?: WorktreePruneOptions | null | undefined): boolean; + /// } + /// ``` + /// + /// @param {WorktreePruneOptions} [options] - Options for checking if the worktree is prunable. + /// @returns `true` if the worktree is prunable, `false` otherwise. + /// @throws Throws error if checking fails. + pub fn is_prunable(&self, worktree_prune_options: Option) -> crate::Result { + let mut git2_worktree_prune_options = worktree_prune_options.map(git2::WorktreePruneOptions::from); + self + .inner + .is_prunable(git2_worktree_prune_options.as_mut()) + .map_err(crate::Error::from) + } +} + +#[napi] +impl Repository { + #[napi] + /// Add a new worktree to the repository. + /// + /// @category Repository/Methods + /// + /// @signature + /// ```ts + /// class Repository { + /// worktree(name: string, path: string, options?: WorktreeAddOptions | null | undefined): Worktree; + /// } + /// ``` + /// + /// @param {string} name - Name of the worktree to add. + /// @param {string} path - Path where the worktree should be created. + /// @param {WorktreeAddOptions} [options] - Options for adding the worktree. + /// @returns New worktree instance. + /// @throws Throws error if adding the worktree fails (e.g., path already exists, invalid reference name, or filesystem errors). + pub fn worktree( + &self, + this: Reference, + env: Env, + name: String, + path: String, + options: Option, + ) -> crate::Result { + let mut git2_opts = git2::WorktreeAddOptions::new(); + // add non reference options + if let Some(ref _options) = options { + _options.lock.map(|_lock| git2_opts.lock(_lock)); + _options + .checkout_existing + .map(|_checkout_existing| git2_opts.checkout_existing(_checkout_existing)); + } + + // add reference option + let git2_reference = options + .as_ref() + .and_then(|opts| opts.ref_name.as_ref()) + .map(|ref_name| self.inner.find_reference(ref_name)) + .transpose()?; + git2_opts.reference(git2_reference.as_ref()); + + // add worktree + let git2_worktree = this.share_with(env, |repo| { + repo + .inner + .worktree(&name, Path::new(&path), Some(&git2_opts)) + .map_err(crate::Error::from) + .map_err(|e| e.into()) + })?; + + Ok(Worktree { + inner: WorktreeInner::Repo(git2_worktree), + }) + } + + #[napi] + /// List all worktrees in the repository. + /// + /// @category Repository/Methods + /// + /// @signature + /// ```ts + /// class Repository { + /// worktrees(): string[]; + /// } + /// ``` + /// + /// @returns Array of worktree names. + /// @throws Throws error if listing worktrees fails (e.g., filesystem errors or repository corruption). + pub fn worktrees(&self) -> crate::Result> { + let git2_worktrees = self.inner.worktrees()?; + let worktree_names: Vec = git2_worktrees + .iter() + .filter_map(|name| name.map(ToString::to_string)) + .collect::>(); + Ok(worktree_names) + } + + #[napi] + /// Tests whether this repository is a worktree. + /// + /// @category Repository/Methods + /// @signature + /// ```ts + /// class Repository { + /// isWorktree(): boolean; + /// } + /// ``` + /// + /// @returns Returns `true` if repository is a worktree. + pub fn is_worktree(&self) -> bool { + self.inner.is_worktree() + } + + #[napi] + /// Find a worktree by name. + /// + /// @category Repository/Methods + /// + /// @signature + /// ```ts + /// class Repository { + /// findWorktree(name: string): Worktree; + /// } + /// ``` + /// + /// @param {string} name - Name of the worktree to find. + /// @returns Worktree instance. + /// @throws Throws error if the worktree is not found or if opening fails. + pub fn find_worktree(&self, this: Reference, env: Env, name: String) -> crate::Result { + let git2_worktree = this.share_with(env, |repo| { + repo + .inner + .find_worktree(&name) + .map_err(crate::Error::from) + .map_err(|e| e.into()) + })?; + Ok(Worktree { + inner: WorktreeInner::Repo(git2_worktree), + }) + } + + #[napi] + /// Open a repository from a worktree. + /// + /// @category Repository/Methods + /// + /// @signature + /// ```ts + /// class Repository { + /// static openFromWorktree(worktree: Worktree): Repository; + /// } + /// ``` + /// + /// @param {Worktree} worktree - Worktree to open repository from. + /// @returns Repository instance. + /// @throws Throws error if opening the repository fails. + pub fn open_from_worktree(worktree: &Worktree) -> crate::Result { + let git2_repository = git2::Repository::open_from_worktree(&worktree.inner)?; + Ok(Repository { inner: git2_repository }) + } +} diff --git a/tests/worktree.spec.ts b/tests/worktree.spec.ts new file mode 100644 index 0000000..e69de29 From d3405d7ddf0e5ed486dd9641ca295b93606a8dc8 Mon Sep 17 00:00:00 2001 From: racgoo Date: Sun, 28 Dec 2025 20:59:16 +0900 Subject: [PATCH 02/11] refactor: change WorktreeLockStatus from enum to struct --- index.d.ts | 39 +++++++++++++++------------------------ index.js | 1 + src/worktree.rs | 23 +++++++++++++++++++---- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/index.d.ts b/index.d.ts index fb4fe95..c85ce99 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5173,7 +5173,7 @@ export declare class Repository { * @param {string} path - Path where the worktree should be created. * @param {WorktreeAddOptions} [options] - Options for adding the worktree. * @returns New worktree instance. - * @throws Throws error if adding the worktree fails. + * @throws Throws error if adding the worktree fails (e.g., path already exists, invalid reference name, or filesystem errors). */ worktree(name: string, path: string, options?: WorktreeAddOptions | undefined | null): Worktree /** @@ -5189,7 +5189,7 @@ export declare class Repository { * ``` * * @returns Array of worktree names. - * @throws Throws error if listing worktrees fails. + * @throws Throws error if listing worktrees fails (e.g., filesystem errors or repository corruption). */ worktrees(): Array /** @@ -9202,58 +9202,49 @@ export type TreeWalkMode = 'PreOrder'| export interface WorktreeAddOptions { /** * If enabled, this will cause the newly added worktree to be locked. - * - * Locking prevents the worktree from being pruned or deleted inadvertently. - * This is useful for worktrees stored on removable devices or network shares - * that may not always be accessible. - * * Defaults to `false`. */ lock?: boolean /** * If enabled, this will checkout the existing branch matching the worktree name. - * - * When creating a worktree, if a branch with the same name as the worktree - * already exists, this option allows checking out that branch instead of - * creating a new one. - * * Defaults to `false`. */ checkoutExisting?: boolean /** - * Reference to use for the new worktree HEAD. - * - * This should be a reference name (e.g., `"refs/heads/main"`). If not provided, - * the worktree will checkout the branch that HEAD currently points to in the - * main repository. - * + * reference name to use for the new worktree HEAD * Defaults to `null`. */ refName?: string } /** Lock Status of a worktree */ -export type WorktreeLockStatus = - | { type: 'Unlocked' } - | { type: 'Locked', field0?: string } +export interface WorktreeLockStatus { + /** Worktree is Unlocked */ + status: WorktreeLockStatusType + /** Worktree is locked with the optional message */ + reason?: string +} + +/** Lock Status of a worktree */ +export type WorktreeLockStatusType = /** Worktree is Unlocked */ +'Unlocked'| +/** Worktree is locked with the optional message */ +'Locked'; /** Options to configure how worktree pruning is performed. */ export interface WorktreePruneOptions { /** * Controls whether valid (still existing on the filesystem) worktrees will be pruned. - * * Defaults to `false`. */ valid?: boolean /** * Controls whether locked worktrees will be pruned. - * * Defaults to `false`. */ locked?: boolean /** * Controls whether the actual working tree on the filesystem is recursively removed. - * * Defaults to `false`. */ workingTree?: boolean diff --git a/index.js b/index.js index 3e8415e..1c290d6 100644 --- a/index.js +++ b/index.js @@ -669,4 +669,5 @@ module.exports.traceClear = nativeBinding.traceClear module.exports.TraceLevel = nativeBinding.TraceLevel module.exports.traceSet = nativeBinding.traceSet module.exports.TreeWalkMode = nativeBinding.TreeWalkMode +module.exports.WorktreeLockStatusType = nativeBinding.WorktreeLockStatusType module.exports.zeroOid = nativeBinding.zeroOid diff --git a/src/worktree.rs b/src/worktree.rs index bc31544..de8f0d6 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -6,13 +6,22 @@ use napi_derive::napi; use std::ops::Deref; use std::path::Path; +#[napi(object)] +/// Lock Status of a worktree +pub struct WorktreeLockStatus { + /// Worktree is Unlocked + pub status: WorktreeLockStatusType, + /// Worktree is locked with the optional message + pub reason: Option, +} +// (Option) #[napi(string_enum)] /// Lock Status of a worktree -pub enum WorktreeLockStatus { +pub enum WorktreeLockStatusType { /// Worktree is Unlocked Unlocked, /// Worktree is locked with the optional message - Locked(Option), + Locked, } #[napi(object)] @@ -62,8 +71,14 @@ impl From for git2::WorktreePruneOptions { impl From for WorktreeLockStatus { fn from(value: git2::WorktreeLockStatus) -> Self { match value { - git2::WorktreeLockStatus::Unlocked => WorktreeLockStatus::Unlocked, - git2::WorktreeLockStatus::Locked(reason) => WorktreeLockStatus::Locked(reason), + git2::WorktreeLockStatus::Unlocked => WorktreeLockStatus { + status: WorktreeLockStatusType::Unlocked, + reason: None, + }, + git2::WorktreeLockStatus::Locked(reason) => WorktreeLockStatus { + status: WorktreeLockStatusType::Locked, + reason, + }, } } } From 1dcb6b7ff358a363d4bbab02fe008862e3b461d9 Mon Sep 17 00:00:00 2001 From: racgoo Date: Sun, 28 Dec 2025 21:13:42 +0900 Subject: [PATCH 03/11] docs: add spacing in Options --- index.d.ts | 6 ++++++ src/worktree.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/index.d.ts b/index.d.ts index c85ce99..e24140c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -9202,16 +9202,19 @@ export type TreeWalkMode = 'PreOrder'| export interface WorktreeAddOptions { /** * If enabled, this will cause the newly added worktree to be locked. + * * Defaults to `false`. */ lock?: boolean /** * If enabled, this will checkout the existing branch matching the worktree name. + * * Defaults to `false`. */ checkoutExisting?: boolean /** * reference name to use for the new worktree HEAD + * * Defaults to `null`. */ refName?: string @@ -9235,16 +9238,19 @@ export type WorktreeLockStatusType = /** Worktree is Unlocked */ export interface WorktreePruneOptions { /** * Controls whether valid (still existing on the filesystem) worktrees will be pruned. + * * Defaults to `false`. */ valid?: boolean /** * Controls whether locked worktrees will be pruned. + * * Defaults to `false`. */ locked?: boolean /** * Controls whether the actual working tree on the filesystem is recursively removed. + * * Defaults to `false`. */ workingTree?: boolean diff --git a/src/worktree.rs b/src/worktree.rs index de8f0d6..ace1f97 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -28,14 +28,17 @@ pub enum WorktreeLockStatusType { /// Options for adding a worktree. pub struct WorktreeAddOptions { /// If enabled, this will cause the newly added worktree to be locked. + /// /// Defaults to `false`. pub lock: Option, /// If enabled, this will checkout the existing branch matching the worktree name. + /// /// Defaults to `false`. pub checkout_existing: Option, /// reference name to use for the new worktree HEAD + /// /// Defaults to `null`. pub ref_name: Option, } @@ -44,14 +47,17 @@ pub struct WorktreeAddOptions { /// Options to configure how worktree pruning is performed. pub struct WorktreePruneOptions { /// Controls whether valid (still existing on the filesystem) worktrees will be pruned. + /// /// Defaults to `false`. pub valid: Option, /// Controls whether locked worktrees will be pruned. + /// /// Defaults to `false`. pub locked: Option, /// Controls whether the actual working tree on the filesystem is recursively removed. + /// /// Defaults to `false`. pub working_tree: Option, } From 78ed08c0d8816b0ef99d3ff83d81af2df0f09d89 Mon Sep 17 00:00:00 2001 From: racgoo Date: Sun, 28 Dec 2025 21:15:59 +0900 Subject: [PATCH 04/11] test: add worktree test --- src/worktree.rs | 12 +- tests/worktree.spec.ts | 264 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+), 6 deletions(-) diff --git a/src/worktree.rs b/src/worktree.rs index ace1f97..2d40278 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -28,17 +28,17 @@ pub enum WorktreeLockStatusType { /// Options for adding a worktree. pub struct WorktreeAddOptions { /// If enabled, this will cause the newly added worktree to be locked. - /// + /// /// Defaults to `false`. pub lock: Option, /// If enabled, this will checkout the existing branch matching the worktree name. - /// + /// /// Defaults to `false`. pub checkout_existing: Option, /// reference name to use for the new worktree HEAD - /// + /// /// Defaults to `null`. pub ref_name: Option, } @@ -47,17 +47,17 @@ pub struct WorktreeAddOptions { /// Options to configure how worktree pruning is performed. pub struct WorktreePruneOptions { /// Controls whether valid (still existing on the filesystem) worktrees will be pruned. - /// + /// /// Defaults to `false`. pub valid: Option, /// Controls whether locked worktrees will be pruned. - /// + /// /// Defaults to `false`. pub locked: Option, /// Controls whether the actual working tree on the filesystem is recursively removed. - /// + /// /// Defaults to `false`. pub working_tree: Option, } diff --git a/tests/worktree.spec.ts b/tests/worktree.spec.ts index e69de29..4351f3d 100644 --- a/tests/worktree.spec.ts +++ b/tests/worktree.spec.ts @@ -0,0 +1,264 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { Repository, Worktree, openRepository } from '../index'; +import { useFixture } from './fixtures'; +import { makeTmpDir } from './tmp'; + +describe('worktree', () => { + const signature = { name: 'racgoo', email: 'racgoo@example.com' }; + let repo: Repository; + let baseWorktreePath: string; + + beforeEach(async () => { + const p = await useFixture('empty'); + repo = await openRepository(p); + const config = repo.config(); + config.setString('user.name', signature.name); + config.setString('user.email', signature.email); + // Create initial commit + const oid = repo.commit(repo.getTree(repo.index().writeTree()), 'initial commit', { + updateRef: 'HEAD', + author: signature, + committer: signature, + parents: [repo.head().target()!], + }); + // Create a branch for worktree + repo.createBranch('worktree-branch', repo.getCommit(oid)); + // Create base temporary directory for worktrees + baseWorktreePath = await makeTmpDir('worktree-test'); + }); + + afterEach(async () => { + // Clean up worktrees + const worktrees = repo.worktrees(); + for (const name of worktrees) { + repo.findWorktree(name).prune({ valid: true, locked: true, workingTree: true }); + } + // Remove base worktree directory + await fs.rm(baseWorktreePath, { recursive: true, force: true }); + repo.cleanupState(); + }); + + it('add worktree', async () => { + // Generate worktree + const worktreeName = 'test'; + const worktreePath = path.join(baseWorktreePath, 'test-dir'); + const worktree = repo.worktree(worktreeName, worktreePath); + expect(worktree).toBeDefined(); + + // Open test-worktree repository (path based) + const originRepoHeadName = repo.head().name(); + const worktreeRepo = Repository.openFromWorktree(worktree); + const head = worktreeRepo.head(); + expect(head.name()).include(worktreeName); + expect(head.name()).not.toBe(originRepoHeadName); + }); + + it('add worktree with options', async () => { + const worktreeName = 'test'; + const worktreePath = path.join(baseWorktreePath, 'test-dir'); + const worktree = repo.worktree(worktreeName, worktreePath, { + lock: true, + checkoutExisting: false, + refName: 'refs/heads/worktree-branch', + }); + expect(worktree).toBeDefined(); + expect(worktree.name()).toBe(worktreeName); + + const lockStatus = worktree.isLocked(); + expect(lockStatus).toBeDefined(); + expect(lockStatus.status).toBe('Locked'); + + // Open test-worktree repository(reference based) + const worktreeRepo = Repository.openFromWorktree(worktree); + const head = worktreeRepo.head(); + expect(head.name()).toBe('refs/heads/worktree-branch'); + }); + + it('list worktrees', async () => { + const worktree1 = repo.worktree('worktree1', path.join(baseWorktreePath, 'wt1-dir')); + const worktree2 = repo.worktree('worktree2', path.join(baseWorktreePath, 'wt2-dir')); + + const worktrees = repo.worktrees(); + expect(worktrees).toContain('worktree1'); + expect(worktrees).toContain('worktree2'); + }); + + it('get worktree name and path', async () => { + const worktreeName = 'test'; + const worktreePath = path.join(baseWorktreePath, 'test-dir'); + + const worktree = repo.worktree(worktreeName, worktreePath); + expect(worktree.name()).toBe(worktreeName); + + // Normalize paths to handle symlink differences on macOS + expect(await fs.realpath(worktree.path())).toBe(await fs.realpath(worktreePath)); + }); + + it('lock and unlock worktree', async () => { + const worktreeName = 'test'; + const worktreePath = path.join(baseWorktreePath, 'test-dir'); + const worktree = repo.worktree(worktreeName, worktreePath); + + // Initially unlocked + let lockStatus = worktree.isLocked(); + expect(lockStatus.status).toBe('Unlocked'); + + // Lock with reason + const lockReason = 'test reason'; + worktree.lock(lockReason); + lockStatus = worktree.isLocked(); + expect(lockStatus.status).toBe('Locked'); + expect(lockStatus.reason).toBe(lockReason); + + // Unlock + worktree.unlock(); + lockStatus = worktree.isLocked(); + expect(lockStatus.status).toBe('Unlocked'); + }); + + it('lock worktree without reason', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-lock-null'); + const worktree = repo.worktree('test-worktree', worktreePath); + worktree.lock(null); + const lockStatus = worktree.isLocked(); + expect(lockStatus.status).toBe('Locked'); + expect(lockStatus.reason).toBeUndefined(); + }); + + it('validate worktree', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-validate'); + const worktree = repo.worktree('test-worktree', worktreePath); + expect(() => worktree.validate()).not.toThrow(); + }); + + it('find worktree by name', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-find'); + repo.worktree('test-worktree', worktreePath); + const found = repo.findWorktree('test-worktree'); + expect(found).toBeDefined(); + expect(found.name()).toBe('test-worktree'); + // Normalize paths to handle symlink differences on macOS + expect(await fs.realpath(found.path())).toBe(await fs.realpath(worktreePath)); + }); + + it('find worktree throws error if not found', async () => { + expect(() => repo.findWorktree('non-existent-worktree')).toThrow(); + }); + + it('open repository from worktree', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-open-repo'); + const worktree = repo.worktree('test-worktree', worktreePath); + const worktreeRepo = Repository.openFromWorktree(worktree); + expect(worktreeRepo).toBeDefined(); + expect(worktreeRepo.isWorktree()).toBe(true); + }); + + it('open worktree from repository', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-open-wt'); + const worktree = repo.worktree('test-worktree', worktreePath); + const worktreeRepo = Repository.openFromWorktree(worktree); + const openedWorktree = Worktree.openFromRepository(worktreeRepo); + expect(openedWorktree).toBeDefined(); + expect(openedWorktree.name()).toBe('test-worktree'); + }); + + it('check if repository is worktree', async () => { + expect(repo.isWorktree()).toBe(false); + + const worktreePath = path.join(baseWorktreePath, 'test-worktree-is-wt'); + const worktree = repo.worktree('test-worktree', worktreePath); + const worktreeRepo = Repository.openFromWorktree(worktree); + expect(worktreeRepo.isWorktree()).toBe(true); + }); + + it('check if worktree is prunable', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-prunable'); + const worktree = repo.worktree('test-worktree', worktreePath); + const isPrunable = worktree.isPrunable(); + expect(typeof isPrunable).toBe('boolean'); + }); + + it('check if worktree is prunable with options', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-prunable-opts'); + const worktree = repo.worktree('test-worktree', worktreePath); + const isPrunable = worktree.isPrunable({ + valid: true, + locked: false, + workingTree: false, + }); + expect(typeof isPrunable).toBe('boolean'); + }); + + it('prune worktree', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-prune'); + const worktree = repo.worktree('test-worktree', worktreePath); + const worktreeName = worktree.name(); + expect(worktreeName).toBe('test-worktree'); + + // Prune the worktree + worktree.prune({ + valid: true, + locked: false, + workingTree: true, + }); + + // Worktree should be removed from list + const worktrees = repo.worktrees(); + expect(worktrees).not.toContain('test-worktree'); + }); + + it('add worktree with checkoutExisting option', async () => { + // Create a branch with the same name as worktree + const headOid = repo.head().target()!; + repo.createBranch('existing-branch', repo.getCommit(headOid)); + const commitOid = repo.commit(repo.getTree(repo.index().writeTree()), 'test', { + updateRef: 'refs/heads/existing-branch', + author: signature, + committer: signature, + parents: [headOid], + }); + const worktreePath = path.join(baseWorktreePath, 'test-worktree-checkout-existing'); + const worktree = repo.worktree('existing-branch', worktreePath, { + checkoutExisting: true, + }); + // Check worktree + expect(worktree).toBeDefined(); + expect(worktree.name()).toBe('existing-branch'); + // Open worktree repository and check head + const worktreeRepo = Repository.openFromWorktree(worktree); + const head = worktreeRepo.head(); + expect(head.name()).toBe('refs/heads/existing-branch'); + expect(head.target()).toBe(commitOid); + }); + + it('add worktree with refName option', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-refname'); + const worktree = repo.worktree('test-worktree', worktreePath, { + refName: 'refs/heads/worktree-branch', + }); + expect(worktree).toBeDefined(); + + const worktreeRepo = Repository.openFromWorktree(worktree); + const head = worktreeRepo.head(); + expect(head.name()).toBe('refs/heads/worktree-branch'); + }); + + it('add worktree throws error if path already exists', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-exists'); + // Create a file at the path + await fs.writeFile(worktreePath, 'test'); + + expect(() => repo.worktree('test-worktree', worktreePath)).toThrow(); + }); + + it('add worktree throws error if invalid reference name', async () => { + const worktreePath = path.join(baseWorktreePath, 'test-worktree-invalid-ref'); + expect(() => + repo.worktree('test-worktree', worktreePath, { + refName: 'refs/heads/non-existent', + }) + ).toThrow(); + }); +}); From 866a23c2cdfe80a7c381415ee64facc01ba8340b Mon Sep 17 00:00:00 2001 From: RakHyeon-Sung <44660991+racgoo@users.noreply.github.com> Date: Mon, 29 Dec 2025 11:33:53 +0900 Subject: [PATCH 05/11] Update src/worktree.rs Oh.. it's mistake Co-authored-by: seokju-na --- src/worktree.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/worktree.rs b/src/worktree.rs index 2d40278..ddda8f7 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -14,7 +14,6 @@ pub struct WorktreeLockStatus { /// Worktree is locked with the optional message pub reason: Option, } -// (Option) #[napi(string_enum)] /// Lock Status of a worktree pub enum WorktreeLockStatusType { From ee12d105af1aaa34646dd0bc2c932656d65898e5 Mon Sep 17 00:00:00 2001 From: RakHyeon-Sung <44660991+racgoo@users.noreply.github.com> Date: Mon, 29 Dec 2025 11:37:11 +0900 Subject: [PATCH 06/11] Update src/worktree.rs I used '.map' here for brevity, even though it's not ideal for mutable side effects. Thanks for the suggestion. I'll refactor this to an if let pattern. Co-authored-by: seokju-na --- src/worktree.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/worktree.rs b/src/worktree.rs index ddda8f7..e62bf4f 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -64,7 +64,9 @@ pub struct WorktreePruneOptions { impl From for git2::WorktreePruneOptions { fn from(value: WorktreePruneOptions) -> Self { let mut git2_worktree_prune_options = git2::WorktreePruneOptions::new(); - value.valid.map(|_valid| git2_worktree_prune_options.valid(_valid)); + if let Some(valid) = value.valid { + git2_worktree_prune_options.valid(valod); + } value.valid.map(|_locked| git2_worktree_prune_options.locked(_locked)); value .valid From cada335f769bfacaba4f46e451fdb896fdeaa375 Mon Sep 17 00:00:00 2001 From: RakHyeon-Sung <44660991+racgoo@users.noreply.github.com> Date: Mon, 29 Dec 2025 11:39:03 +0900 Subject: [PATCH 07/11] Update src/worktree.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same here. I’ll switch this to 'if let' for clarity. Thanks! Co-authored-by: seokju-na --- src/worktree.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/worktree.rs b/src/worktree.rs index e62bf4f..6cdf375 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -67,7 +67,12 @@ impl From for git2::WorktreePruneOptions { if let Some(valid) = value.valid { git2_worktree_prune_options.valid(valod); } - value.valid.map(|_locked| git2_worktree_prune_options.locked(_locked)); + if let Some(locked) = value.locked { + // .. + } + if let Some(working_tree) = value.working_tree { + // .. + } value .valid .map(|_working_tree| git2_worktree_prune_options.working_tree(_working_tree)); From c9ec9933a2e12dc282be5485403cb74307d24c0d Mon Sep 17 00:00:00 2001 From: racgoo Date: Mon, 29 Dec 2025 11:47:29 +0900 Subject: [PATCH 08/11] refactor: change mutable behavior of '.map' pattern to 'if let' pattern --- src/worktree.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/worktree.rs b/src/worktree.rs index 6cdf375..a03609f 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -65,17 +65,14 @@ impl From for git2::WorktreePruneOptions { fn from(value: WorktreePruneOptions) -> Self { let mut git2_worktree_prune_options = git2::WorktreePruneOptions::new(); if let Some(valid) = value.valid { - git2_worktree_prune_options.valid(valod); + git2_worktree_prune_options.valid(valid); } if let Some(locked) = value.locked { - // .. + git2_worktree_prune_options.locked(locked); } if let Some(working_tree) = value.working_tree { - // .. + git2_worktree_prune_options.working_tree(working_tree); } - value - .valid - .map(|_working_tree| git2_worktree_prune_options.working_tree(_working_tree)); git2_worktree_prune_options } } @@ -324,10 +321,12 @@ impl Repository { let mut git2_opts = git2::WorktreeAddOptions::new(); // add non reference options if let Some(ref _options) = options { - _options.lock.map(|_lock| git2_opts.lock(_lock)); - _options - .checkout_existing - .map(|_checkout_existing| git2_opts.checkout_existing(_checkout_existing)); + if let Some(lock) = _options.lock { + git2_opts.lock(lock); + } + if let Some(checkout_existing) = _options.checkout_existing { + git2_opts.checkout_existing(checkout_existing); + } } // add reference option From 3ea5efa89519de0681aa8f95a463b861cea9dc39 Mon Sep 17 00:00:00 2001 From: racgoo Date: Mon, 29 Dec 2025 13:11:10 +0900 Subject: [PATCH 09/11] refactor: extract worktree/repository open methods to standalone functions and use Owned --- index.d.ts | 93 +++++++++++++++++++++------------ index.js | 2 + src/repository.rs | 32 ++++++++++++ src/worktree.rs | 116 +++++++++++++++-------------------------- tests/worktree.spec.ts | 18 +++---- 5 files changed, 143 insertions(+), 118 deletions(-) diff --git a/index.d.ts b/index.d.ts index d0ab2a0..649b9a2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5237,23 +5237,6 @@ export declare class Repository { * @throws Throws error if the worktree is not found or if opening fails. */ findWorktree(name: string): Worktree - /** - * Open a repository from a worktree. - * - * @category Repository/Methods - * - * @signature - * ```ts - * class Repository { - * static openFromWorktree(worktree: Worktree): Repository; - * } - * ``` - * - * @param {Worktree} worktree - Worktree to open repository from. - * @returns Repository instance. - * @throws Throws error if opening the repository fails. - */ - static openFromWorktree(worktree: Worktree): Repository } /** @@ -6522,23 +6505,6 @@ export declare class TreeIter extends Iterator { /** A class to represent a git worktree. */ export declare class Worktree { - /** - * Open a worktree from a repository. - * - * @category Worktree/Methods - * - * @signature - * ```ts - * class Worktree { - * static openFromRepository(repo: Repository): Worktree; - * } - * ``` - * - * @param {Repository} repo - Repository to open worktree from. - * @returns Worktree instance. - * @throws Throws error if the repository is not a worktree or if opening fails. - */ - static openFromRepository(repo: Repository): Worktree /** * Get the name of this worktree. * @@ -8337,6 +8303,65 @@ export declare function openDefaultConfig(): Config */ export declare function openRepository(path: string, options?: RepositoryOpenOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise +/** + * Open a repository from a worktree. + * + * This will open the repository associated with the given worktree. + * + * @category Repository + * + * @signature + * ```ts + * function openRepositoryFromWorktree(worktree: Worktree): Repository; + * ``` + * + * @param {Worktree} worktree - Worktree to open repository from. + * @returns Repository instance. + * @throws Throws error if opening the repository fails. + * + * @example + * + * Open a repository from a worktree. + * + * ```ts + * import { openWorktreeFromRepository, openRepositoryFromWorktree } from 'es-git'; + * + * const worktree = openWorktreeFromRepository(repo); + * const repo = openRepositoryFromWorktree(worktree); + * ``` + */ +export declare function openRepositoryFromWorktree(worktree: Worktree): Repository + +/** + * Open a worktree from a repository. + * + * This will open the worktree associated with the given repository if the + * repository is a worktree. + * + * @category Worktree + * + * @signature + * ```ts + * function openWorktreeFromRepository(repo: Repository): Worktree; + * ``` + * + * @param {Repository} repo - Repository to open worktree from. + * @returns Worktree instance. + * @throws Throws error if the repository is not a worktree or if opening fails. + * + * @example + * + * Open a worktree from a repository. + * + * ```ts + * import { openRepository, openWorktreeFromRepository } from 'es-git'; + * + * const repo = await openRepository('.'); + * const worktree = openWorktreeFromRepository(repo); + * ``` + */ +export declare function openWorktreeFromRepository(repo: Repository): Worktree + /** * Parse a string as a bool. * diff --git a/index.js b/index.js index 1c290d6..bb58683 100644 --- a/index.js +++ b/index.js @@ -648,6 +648,8 @@ module.exports.ObjectType = nativeBinding.ObjectType module.exports.openConfig = nativeBinding.openConfig module.exports.openDefaultConfig = nativeBinding.openDefaultConfig module.exports.openRepository = nativeBinding.openRepository +module.exports.openRepositoryFromWorktree = nativeBinding.openRepositoryFromWorktree +module.exports.openWorktreeFromRepository = nativeBinding.openWorktreeFromRepository module.exports.parseConfigBool = nativeBinding.parseConfigBool module.exports.parseConfigI32 = nativeBinding.parseConfigI32 module.exports.parseConfigI64 = nativeBinding.parseConfigI64 diff --git a/src/repository.rs b/src/repository.rs index a96f429..2cea0c3 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -2,6 +2,7 @@ use crate::annotated_commit::AnnotatedCommit; use crate::commit::Commit; use crate::remote::FetchOptions; use crate::util; +use crate::worktree::Worktree; use napi::bindgen_prelude::*; use napi_derive::napi; use std::path::Path; @@ -860,3 +861,34 @@ pub fn clone_repository( ) -> AsyncTask { AsyncTask::with_optional_signal(CloneRepositoryTask { url, path, options }, signal) } + +#[napi] +/// Open a repository from a worktree. +/// +/// This will open the repository associated with the given worktree. +/// +/// @category Repository +/// +/// @signature +/// ```ts +/// function openRepositoryFromWorktree(worktree: Worktree): Repository; +/// ``` +/// +/// @param {Worktree} worktree - Worktree to open repository from. +/// @returns Repository instance. +/// @throws Throws error if opening the repository fails. +/// +/// @example +/// +/// Open a repository from a worktree. +/// +/// ```ts +/// import { openWorktreeFromRepository, openRepositoryFromWorktree } from 'es-git'; +/// +/// const worktree = openWorktreeFromRepository(repo); +/// const repo = openRepositoryFromWorktree(worktree); +/// ``` +pub fn open_repository_from_worktree(worktree: &Worktree) -> crate::Result { + let git2_repository: git2::Repository = git2::Repository::open_from_worktree(&worktree.inner)?; + Ok(Repository { inner: git2_repository }) +} diff --git a/src/worktree.rs b/src/worktree.rs index a03609f..f5357fc 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -1,7 +1,5 @@ use crate::repository::Repository; use crate::util::path_to_string; -use napi::bindgen_prelude::{Reference, SharedReference}; -use napi::Env; use napi_derive::napi; use std::ops::Deref; use std::path::Path; @@ -93,7 +91,7 @@ impl From for WorktreeLockStatus { } pub(crate) enum WorktreeInner { - Repo(SharedReference), + Owned(git2::Worktree), } impl Deref for WorktreeInner { @@ -101,7 +99,7 @@ impl Deref for WorktreeInner { fn deref(&self) -> &Self::Target { match self { - Self::Repo(inner) => inner.deref(), + Self::Owned(inner) => inner, } } } @@ -114,32 +112,6 @@ pub struct Worktree { #[napi] impl Worktree { - #[napi] - /// Open a worktree from a repository. - /// - /// @category Worktree/Methods - /// - /// @signature - /// ```ts - /// class Worktree { - /// static openFromRepository(repo: Repository): Worktree; - /// } - /// ``` - /// - /// @param {Repository} repo - Repository to open worktree from. - /// @returns Worktree instance. - /// @throws Throws error if the repository is not a worktree or if opening fails. - pub fn open_from_repository(repo: Reference, env: Env) -> crate::Result { - let worktree = repo.share_with(env, |repo| { - git2::Worktree::open_from_repository(&repo.inner) - .map_err(crate::Error::from) - .map_err(|e| e.into()) - })?; - Ok(Worktree { - inner: WorktreeInner::Repo(worktree), - }) - } - #[napi] /// Get the name of this worktree. /// @@ -310,14 +282,7 @@ impl Repository { /// @param {WorktreeAddOptions} [options] - Options for adding the worktree. /// @returns New worktree instance. /// @throws Throws error if adding the worktree fails (e.g., path already exists, invalid reference name, or filesystem errors). - pub fn worktree( - &self, - this: Reference, - env: Env, - name: String, - path: String, - options: Option, - ) -> crate::Result { + pub fn worktree(&self, name: String, path: String, options: Option) -> crate::Result { let mut git2_opts = git2::WorktreeAddOptions::new(); // add non reference options if let Some(ref _options) = options { @@ -338,16 +303,9 @@ impl Repository { git2_opts.reference(git2_reference.as_ref()); // add worktree - let git2_worktree = this.share_with(env, |repo| { - repo - .inner - .worktree(&name, Path::new(&path), Some(&git2_opts)) - .map_err(crate::Error::from) - .map_err(|e| e.into()) - })?; - + let git2_worktree = self.inner.worktree(&name, Path::new(&path), Some(&git2_opts))?; Ok(Worktree { - inner: WorktreeInner::Repo(git2_worktree), + inner: WorktreeInner::Owned(git2_worktree), }) } @@ -405,36 +363,44 @@ impl Repository { /// @param {string} name - Name of the worktree to find. /// @returns Worktree instance. /// @throws Throws error if the worktree is not found or if opening fails. - pub fn find_worktree(&self, this: Reference, env: Env, name: String) -> crate::Result { - let git2_worktree = this.share_with(env, |repo| { - repo - .inner - .find_worktree(&name) - .map_err(crate::Error::from) - .map_err(|e| e.into()) - })?; + pub fn find_worktree(&self, name: String) -> crate::Result { + let git2_worktree = self.inner.find_worktree(&name)?; Ok(Worktree { - inner: WorktreeInner::Repo(git2_worktree), + inner: WorktreeInner::Owned(git2_worktree), }) } +} - #[napi] - /// Open a repository from a worktree. - /// - /// @category Repository/Methods - /// - /// @signature - /// ```ts - /// class Repository { - /// static openFromWorktree(worktree: Worktree): Repository; - /// } - /// ``` - /// - /// @param {Worktree} worktree - Worktree to open repository from. - /// @returns Repository instance. - /// @throws Throws error if opening the repository fails. - pub fn open_from_worktree(worktree: &Worktree) -> crate::Result { - let git2_repository = git2::Repository::open_from_worktree(&worktree.inner)?; - Ok(Repository { inner: git2_repository }) - } +#[napi] +/// Open a worktree from a repository. +/// +/// This will open the worktree associated with the given repository if the +/// repository is a worktree. +/// +/// @category Worktree +/// +/// @signature +/// ```ts +/// function openWorktreeFromRepository(repo: Repository): Worktree; +/// ``` +/// +/// @param {Repository} repo - Repository to open worktree from. +/// @returns Worktree instance. +/// @throws Throws error if the repository is not a worktree or if opening fails. +/// +/// @example +/// +/// Open a worktree from a repository. +/// +/// ```ts +/// import { openRepository, openWorktreeFromRepository } from 'es-git'; +/// +/// const repo = await openRepository('.'); +/// const worktree = openWorktreeFromRepository(repo); +/// ``` +pub fn open_worktree_from_repository(repo: &Repository) -> crate::Result { + let worktree = git2::Worktree::open_from_repository(&repo.inner).map_err(crate::Error::from)?; + Ok(Worktree { + inner: WorktreeInner::Owned(worktree), + }) } diff --git a/tests/worktree.spec.ts b/tests/worktree.spec.ts index 4351f3d..b19ce23 100644 --- a/tests/worktree.spec.ts +++ b/tests/worktree.spec.ts @@ -1,7 +1,7 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { Repository, Worktree, openRepository } from '../index'; +import { type Repository, openRepository, openRepositoryFromWorktree, openWorktreeFromRepository } from '../index'; import { useFixture } from './fixtures'; import { makeTmpDir } from './tmp'; @@ -49,7 +49,7 @@ describe('worktree', () => { // Open test-worktree repository (path based) const originRepoHeadName = repo.head().name(); - const worktreeRepo = Repository.openFromWorktree(worktree); + const worktreeRepo = openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).include(worktreeName); expect(head.name()).not.toBe(originRepoHeadName); @@ -71,7 +71,7 @@ describe('worktree', () => { expect(lockStatus.status).toBe('Locked'); // Open test-worktree repository(reference based) - const worktreeRepo = Repository.openFromWorktree(worktree); + const worktreeRepo = openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).toBe('refs/heads/worktree-branch'); }); @@ -150,7 +150,7 @@ describe('worktree', () => { it('open repository from worktree', async () => { const worktreePath = path.join(baseWorktreePath, 'test-worktree-open-repo'); const worktree = repo.worktree('test-worktree', worktreePath); - const worktreeRepo = Repository.openFromWorktree(worktree); + const worktreeRepo = openRepositoryFromWorktree(worktree); expect(worktreeRepo).toBeDefined(); expect(worktreeRepo.isWorktree()).toBe(true); }); @@ -158,8 +158,8 @@ describe('worktree', () => { it('open worktree from repository', async () => { const worktreePath = path.join(baseWorktreePath, 'test-worktree-open-wt'); const worktree = repo.worktree('test-worktree', worktreePath); - const worktreeRepo = Repository.openFromWorktree(worktree); - const openedWorktree = Worktree.openFromRepository(worktreeRepo); + const worktreeRepo = openRepositoryFromWorktree(worktree); + const openedWorktree = openWorktreeFromRepository(worktreeRepo); expect(openedWorktree).toBeDefined(); expect(openedWorktree.name()).toBe('test-worktree'); }); @@ -169,7 +169,7 @@ describe('worktree', () => { const worktreePath = path.join(baseWorktreePath, 'test-worktree-is-wt'); const worktree = repo.worktree('test-worktree', worktreePath); - const worktreeRepo = Repository.openFromWorktree(worktree); + const worktreeRepo = openRepositoryFromWorktree(worktree); expect(worktreeRepo.isWorktree()).toBe(true); }); @@ -227,7 +227,7 @@ describe('worktree', () => { expect(worktree).toBeDefined(); expect(worktree.name()).toBe('existing-branch'); // Open worktree repository and check head - const worktreeRepo = Repository.openFromWorktree(worktree); + const worktreeRepo = openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).toBe('refs/heads/existing-branch'); expect(head.target()).toBe(commitOid); @@ -240,7 +240,7 @@ describe('worktree', () => { }); expect(worktree).toBeDefined(); - const worktreeRepo = Repository.openFromWorktree(worktree); + const worktreeRepo = openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).toBe('refs/heads/worktree-branch'); }); From d1da35a2c87fb9f238a8202afa9c86a9db34cf84 Mon Sep 17 00:00:00 2001 From: racgoo Date: Fri, 2 Jan 2026 23:00:59 +0900 Subject: [PATCH 10/11] refactor: make worktree/repository open functions Promise-based --- Cargo.lock | 126 +++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 2 +- index.d.ts | 18 +++--- src/repository.rs | 18 +++--- src/util.rs | 28 +++++++++ src/worktree.rs | 19 ++++--- tests/worktree.spec.ts | 16 +++--- 7 files changed, 188 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b4c38b..49fd12c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,6 +145,95 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "git2" version = "0.20.2" @@ -409,15 +498,22 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + [[package]] name = "napi" -version = "3.5.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d00c1a7ffcf62e0889630f122f8920383f5a9ce4b54377b05c2833fb6123857" +checksum = "000f205daae6646003fdc38517be6232af2b150bad4b67bdaf4c5aadb119d738" dependencies = [ "bitflags", "chrono", "ctor", + "futures", "napi-build", "napi-sys", "nohash-hasher", @@ -426,9 +522,9 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68064c4cf827376751236ee6785e0e38a6461f83a7a7f227c89f6256f3e96cc2" +checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1" [[package]] name = "napi-derive" @@ -459,9 +555,9 @@ dependencies = [ [[package]] name = "napi-sys" -version = "3.1.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f200fd782433de18d46d496223be780837b2f3772e5816f4425e0520bff26c2" +checksum = "8eb602b84d7c1edae45e50bbf1374696548f36ae179dfa667f577e384bb90c2b" dependencies = [ "libloading", ] @@ -521,6 +617,18 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkg-config" version = "0.3.31" @@ -589,6 +697,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + [[package]] name = "smallvec" version = "1.15.0" diff --git a/Cargo.toml b/Cargo.toml index 8edda7a..37a60a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] bitflags = "2.1.0" chrono = "0.4" git2 = { version = "0.20.2", features = ["vendored-libgit2", "vendored-openssl"] } -napi = { version = "3.5.0", default-features = false, features = ["napi6", "chrono_date"] } +napi = { version = "3.7.1", default-features = false, features = ["napi6", "chrono_date"] } napi-derive = "3.3.0" thiserror = "2.0.3" diff --git a/index.d.ts b/index.d.ts index 649b9a2..b09479d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -8312,11 +8312,11 @@ export declare function openRepository(path: string, options?: RepositoryOpenOpt * * @signature * ```ts - * function openRepositoryFromWorktree(worktree: Worktree): Repository; + * function openRepositoryFromWorktree(worktree: Worktree): Promise; * ``` * * @param {Worktree} worktree - Worktree to open repository from. - * @returns Repository instance. + * @returns {Promise} Promise that resolves to a Repository instance. * @throws Throws error if opening the repository fails. * * @example @@ -8326,11 +8326,11 @@ export declare function openRepository(path: string, options?: RepositoryOpenOpt * ```ts * import { openWorktreeFromRepository, openRepositoryFromWorktree } from 'es-git'; * - * const worktree = openWorktreeFromRepository(repo); - * const repo = openRepositoryFromWorktree(worktree); + * const worktree = await openWorktreeFromRepository(repo); + * const repo = await openRepositoryFromWorktree(worktree); * ``` */ -export declare function openRepositoryFromWorktree(worktree: Worktree): Repository +export declare function openRepositoryFromWorktree(worktree: Worktree): Promise /** * Open a worktree from a repository. @@ -8342,11 +8342,11 @@ export declare function openRepositoryFromWorktree(worktree: Worktree): Reposito * * @signature * ```ts - * function openWorktreeFromRepository(repo: Repository): Worktree; + * function openWorktreeFromRepository(repo: Repository): Promise; * ``` * * @param {Repository} repo - Repository to open worktree from. - * @returns Worktree instance. + * @returns {Promise} Promise that resolves to a Worktree instance. * @throws Throws error if the repository is not a worktree or if opening fails. * * @example @@ -8357,10 +8357,10 @@ export declare function openRepositoryFromWorktree(worktree: Worktree): Reposito * import { openRepository, openWorktreeFromRepository } from 'es-git'; * * const repo = await openRepository('.'); - * const worktree = openWorktreeFromRepository(repo); + * const worktree = await openWorktreeFromRepository(repo); * ``` */ -export declare function openWorktreeFromRepository(repo: Repository): Worktree +export declare function openWorktreeFromRepository(repo: Repository): Promise /** * Parse a string as a bool. diff --git a/src/repository.rs b/src/repository.rs index 2cea0c3..84c414d 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -1,8 +1,8 @@ use crate::annotated_commit::AnnotatedCommit; use crate::commit::Commit; use crate::remote::FetchOptions; -use crate::util; use crate::worktree::Worktree; +use crate::{napi_promise, util}; use napi::bindgen_prelude::*; use napi_derive::napi; use std::path::Path; @@ -871,11 +871,11 @@ pub fn clone_repository( /// /// @signature /// ```ts -/// function openRepositoryFromWorktree(worktree: Worktree): Repository; +/// function openRepositoryFromWorktree(worktree: Worktree): Promise; /// ``` /// /// @param {Worktree} worktree - Worktree to open repository from. -/// @returns Repository instance. +/// @returns {Promise} Promise that resolves to a Repository instance. /// @throws Throws error if opening the repository fails. /// /// @example @@ -885,10 +885,12 @@ pub fn clone_repository( /// ```ts /// import { openWorktreeFromRepository, openRepositoryFromWorktree } from 'es-git'; /// -/// const worktree = openWorktreeFromRepository(repo); -/// const repo = openRepositoryFromWorktree(worktree); +/// const worktree = await openWorktreeFromRepository(repo); +/// const repo = await openRepositoryFromWorktree(worktree); /// ``` -pub fn open_repository_from_worktree(worktree: &Worktree) -> crate::Result { - let git2_repository: git2::Repository = git2::Repository::open_from_worktree(&worktree.inner)?; - Ok(Repository { inner: git2_repository }) +pub fn open_repository_from_worktree(worktree: &Worktree, env: Env) -> PromiseRaw<'_, Repository> { + napi_promise!(&env, || { + let git2_repository = git2::Repository::open_from_worktree(&worktree.inner)?; + Ok(Repository { inner: git2_repository }) + }) } diff --git a/src/util.rs b/src/util.rs index 5000a66..2983ee4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -18,3 +18,31 @@ pub(crate) fn path_to_string(p: &Path) -> String { pub(crate) fn bitflags_contain(source: T, target: T) -> bool { source.contains(target) } + +/// Macro to create a `PromiseRaw` from a closure. +/// +/// - The closure should return `crate::Result` +/// - `Ok(value)` becomes `PromiseRaw::resolve` +/// - `Err(error)` becomes `PromiseRaw::reject` +/// - Errors from `?` operator are automatically converted to rejected promises +/// +/// # Example +/// ```rust,ignore +/// use napi::bindgen_prelude::PromiseRaw; +/// +/// fn my_async_fn(env: Env) -> PromiseRaw<'_, MyType> { +/// napi_promise!(&env, || { +/// let value = some_operation()?; // errors are caught and rejected +/// Ok(MyType { value }) +/// }) +/// } +/// ``` +#[macro_export] +macro_rules! napi_promise { + ($env:expr, || $($body:tt)*) => {{ + match (|| -> $crate::Result<_> { $($body)* })() { + Ok(value) => PromiseRaw::resolve($env, value).expect("napi_promise: failed to create resolved promise"), + Err(error) => PromiseRaw::reject($env, error.to_string()).expect("napi_promise: failed to create rejected promise") + } + }}; +} diff --git a/src/worktree.rs b/src/worktree.rs index f5357fc..a6fbb25 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -1,5 +1,8 @@ +use crate::napi_promise; use crate::repository::Repository; use crate::util::path_to_string; +use napi::bindgen_prelude::PromiseRaw; +use napi::Env; use napi_derive::napi; use std::ops::Deref; use std::path::Path; @@ -381,11 +384,11 @@ impl Repository { /// /// @signature /// ```ts -/// function openWorktreeFromRepository(repo: Repository): Worktree; +/// function openWorktreeFromRepository(repo: Repository): Promise; /// ``` /// /// @param {Repository} repo - Repository to open worktree from. -/// @returns Worktree instance. +/// @returns {Promise} Promise that resolves to a Worktree instance. /// @throws Throws error if the repository is not a worktree or if opening fails. /// /// @example @@ -396,11 +399,13 @@ impl Repository { /// import { openRepository, openWorktreeFromRepository } from 'es-git'; /// /// const repo = await openRepository('.'); -/// const worktree = openWorktreeFromRepository(repo); +/// const worktree = await openWorktreeFromRepository(repo); /// ``` -pub fn open_worktree_from_repository(repo: &Repository) -> crate::Result { - let worktree = git2::Worktree::open_from_repository(&repo.inner).map_err(crate::Error::from)?; - Ok(Worktree { - inner: WorktreeInner::Owned(worktree), +pub fn open_worktree_from_repository(repo: &Repository, env: Env) -> PromiseRaw<'_, Worktree> { + napi_promise!(&env, || { + let worktree = git2::Worktree::open_from_repository(&repo.inner)?; + Ok(Worktree { + inner: WorktreeInner::Owned(worktree), + }) }) } diff --git a/tests/worktree.spec.ts b/tests/worktree.spec.ts index b19ce23..d8a1271 100644 --- a/tests/worktree.spec.ts +++ b/tests/worktree.spec.ts @@ -49,7 +49,7 @@ describe('worktree', () => { // Open test-worktree repository (path based) const originRepoHeadName = repo.head().name(); - const worktreeRepo = openRepositoryFromWorktree(worktree); + const worktreeRepo = await openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).include(worktreeName); expect(head.name()).not.toBe(originRepoHeadName); @@ -71,7 +71,7 @@ describe('worktree', () => { expect(lockStatus.status).toBe('Locked'); // Open test-worktree repository(reference based) - const worktreeRepo = openRepositoryFromWorktree(worktree); + const worktreeRepo = await openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).toBe('refs/heads/worktree-branch'); }); @@ -150,7 +150,7 @@ describe('worktree', () => { it('open repository from worktree', async () => { const worktreePath = path.join(baseWorktreePath, 'test-worktree-open-repo'); const worktree = repo.worktree('test-worktree', worktreePath); - const worktreeRepo = openRepositoryFromWorktree(worktree); + const worktreeRepo = await openRepositoryFromWorktree(worktree); expect(worktreeRepo).toBeDefined(); expect(worktreeRepo.isWorktree()).toBe(true); }); @@ -158,8 +158,8 @@ describe('worktree', () => { it('open worktree from repository', async () => { const worktreePath = path.join(baseWorktreePath, 'test-worktree-open-wt'); const worktree = repo.worktree('test-worktree', worktreePath); - const worktreeRepo = openRepositoryFromWorktree(worktree); - const openedWorktree = openWorktreeFromRepository(worktreeRepo); + const worktreeRepo = await openRepositoryFromWorktree(worktree); + const openedWorktree = await openWorktreeFromRepository(worktreeRepo); expect(openedWorktree).toBeDefined(); expect(openedWorktree.name()).toBe('test-worktree'); }); @@ -169,7 +169,7 @@ describe('worktree', () => { const worktreePath = path.join(baseWorktreePath, 'test-worktree-is-wt'); const worktree = repo.worktree('test-worktree', worktreePath); - const worktreeRepo = openRepositoryFromWorktree(worktree); + const worktreeRepo = await openRepositoryFromWorktree(worktree); expect(worktreeRepo.isWorktree()).toBe(true); }); @@ -227,7 +227,7 @@ describe('worktree', () => { expect(worktree).toBeDefined(); expect(worktree.name()).toBe('existing-branch'); // Open worktree repository and check head - const worktreeRepo = openRepositoryFromWorktree(worktree); + const worktreeRepo = await openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).toBe('refs/heads/existing-branch'); expect(head.target()).toBe(commitOid); @@ -240,7 +240,7 @@ describe('worktree', () => { }); expect(worktree).toBeDefined(); - const worktreeRepo = openRepositoryFromWorktree(worktree); + const worktreeRepo = await openRepositoryFromWorktree(worktree); const head = worktreeRepo.head(); expect(head.name()).toBe('refs/heads/worktree-branch'); }); From e5fc319a22455331ed31aa82fa53f479d3db857c Mon Sep 17 00:00:00 2001 From: racgoo Date: Fri, 2 Jan 2026 23:04:32 +0900 Subject: [PATCH 11/11] chore: update generated index.js bindings --- index.js | 104 +++++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/index.js b/index.js index bb58683..e25c710 100644 --- a/index.js +++ b/index.js @@ -77,8 +77,8 @@ function requireNative() { try { const binding = require('es-git-android-arm64') const bindingPackageVersion = require('es-git-android-arm64/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -93,8 +93,8 @@ function requireNative() { try { const binding = require('es-git-android-arm-eabi') const bindingPackageVersion = require('es-git-android-arm-eabi/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -114,8 +114,8 @@ function requireNative() { try { const binding = require('es-git-win32-x64-gnu') const bindingPackageVersion = require('es-git-win32-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -130,8 +130,8 @@ function requireNative() { try { const binding = require('es-git-win32-x64-msvc') const bindingPackageVersion = require('es-git-win32-x64-msvc/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -147,8 +147,8 @@ function requireNative() { try { const binding = require('es-git-win32-ia32-msvc') const bindingPackageVersion = require('es-git-win32-ia32-msvc/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -163,8 +163,8 @@ function requireNative() { try { const binding = require('es-git-win32-arm64-msvc') const bindingPackageVersion = require('es-git-win32-arm64-msvc/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -182,8 +182,8 @@ function requireNative() { try { const binding = require('es-git-darwin-universal') const bindingPackageVersion = require('es-git-darwin-universal/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -198,8 +198,8 @@ function requireNative() { try { const binding = require('es-git-darwin-x64') const bindingPackageVersion = require('es-git-darwin-x64/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -214,8 +214,8 @@ function requireNative() { try { const binding = require('es-git-darwin-arm64') const bindingPackageVersion = require('es-git-darwin-arm64/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -234,8 +234,8 @@ function requireNative() { try { const binding = require('es-git-freebsd-x64') const bindingPackageVersion = require('es-git-freebsd-x64/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -250,8 +250,8 @@ function requireNative() { try { const binding = require('es-git-freebsd-arm64') const bindingPackageVersion = require('es-git-freebsd-arm64/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -271,8 +271,8 @@ function requireNative() { try { const binding = require('es-git-linux-x64-musl') const bindingPackageVersion = require('es-git-linux-x64-musl/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -287,8 +287,8 @@ function requireNative() { try { const binding = require('es-git-linux-x64-gnu') const bindingPackageVersion = require('es-git-linux-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -305,8 +305,8 @@ function requireNative() { try { const binding = require('es-git-linux-arm64-musl') const bindingPackageVersion = require('es-git-linux-arm64-musl/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -321,8 +321,8 @@ function requireNative() { try { const binding = require('es-git-linux-arm64-gnu') const bindingPackageVersion = require('es-git-linux-arm64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -339,8 +339,8 @@ function requireNative() { try { const binding = require('es-git-linux-arm-musleabihf') const bindingPackageVersion = require('es-git-linux-arm-musleabihf/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -355,8 +355,8 @@ function requireNative() { try { const binding = require('es-git-linux-arm-gnueabihf') const bindingPackageVersion = require('es-git-linux-arm-gnueabihf/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -373,8 +373,8 @@ function requireNative() { try { const binding = require('es-git-linux-loong64-musl') const bindingPackageVersion = require('es-git-linux-loong64-musl/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -389,8 +389,8 @@ function requireNative() { try { const binding = require('es-git-linux-loong64-gnu') const bindingPackageVersion = require('es-git-linux-loong64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -407,8 +407,8 @@ function requireNative() { try { const binding = require('es-git-linux-riscv64-musl') const bindingPackageVersion = require('es-git-linux-riscv64-musl/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -423,8 +423,8 @@ function requireNative() { try { const binding = require('es-git-linux-riscv64-gnu') const bindingPackageVersion = require('es-git-linux-riscv64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -440,8 +440,8 @@ function requireNative() { try { const binding = require('es-git-linux-ppc64-gnu') const bindingPackageVersion = require('es-git-linux-ppc64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -456,8 +456,8 @@ function requireNative() { try { const binding = require('es-git-linux-s390x-gnu') const bindingPackageVersion = require('es-git-linux-s390x-gnu/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -476,8 +476,8 @@ function requireNative() { try { const binding = require('es-git-openharmony-arm64') const bindingPackageVersion = require('es-git-openharmony-arm64/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -492,8 +492,8 @@ function requireNative() { try { const binding = require('es-git-openharmony-x64') const bindingPackageVersion = require('es-git-openharmony-x64/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -508,8 +508,8 @@ function requireNative() { try { const binding = require('es-git-openharmony-arm') const bindingPackageVersion = require('es-git-openharmony-arm/package.json').version - if (bindingPackageVersion !== '0.5.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) {