diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-08 03:12:05 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-08 03:12:05 +0900 |
| commit | e6f35b567564665c6cb741a06e4c4afcdc5ab317 (patch) | |
| tree | a1ae0e55afab95598ff0f6bec5b6a2e9f4f86cc0 /crates/mozart-registry/src/repository/mod.rs | |
| parent | b3fcdf3b5cf0d6b43109c4bcb3dfcbb6576abce5 (diff) | |
| download | php-mozart-e6f35b567564665c6cb741a06e4c4afcdc5ab317.tar.gz php-mozart-e6f35b567564665c6cb741a06e4c4afcdc5ab317.tar.zst php-mozart-e6f35b567564665c6cb741a06e4c4afcdc5ab317.zip | |
fix(search): align with Composer's RepositoryInterface::search
Replace the HTTP-only post-filtered implementation with a Repository::search
trait dispatch that mirrors ComposerRepository::search semantics for all
three modes (FULLTEXT/NAME/VENDOR). --only-name now does an OR-of-tokens
regex match against the full Packagist list.json index instead of a
substring match against a fulltext page, so e.g. \`mozart search --only-name
mono log\` matches \`monolog/monolog\` like Composer does. Other parity
fixes: regex::escape on non-fulltext queries, format check before mutex
check, 4-space JSON indent, OSC 8 terminal hyperlink emission when a
result has a url, <warning>\! Abandoned \!</warning> styling on abandoned
rows, and the Mozart-only "No packages found" warning is dropped to match
Composer's silent empty-result behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart-registry/src/repository/mod.rs')
| -rw-r--r-- | crates/mozart-registry/src/repository/mod.rs | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/crates/mozart-registry/src/repository/mod.rs b/crates/mozart-registry/src/repository/mod.rs index 21752b9..6642638 100644 --- a/crates/mozart-registry/src/repository/mod.rs +++ b/crates/mozart-registry/src/repository/mod.rs @@ -10,12 +10,29 @@ //! the live Packagist HTTP repo, [`inline_package_repo`] for `type: package` //! entries embedded in `composer.json`, and [`vcs_repo`] for VCS repositories. -use crate::packagist::PackagistVersion; +use crate::packagist::{PackagistVersion, SearchResult}; pub mod inline_package_repo; pub mod packagist_repo; pub mod vcs_repo; +/// Search modes for [`Repository::search`]. +/// +/// Mirrors Composer's `RepositoryInterface::SEARCH_FULLTEXT|SEARCH_NAME|SEARCH_VENDOR` +/// constants (`composer/src/Composer/Repository/RepositoryInterface.php`). +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum SearchMode { + /// Full-text search over name, description, and keywords (Packagist's + /// `search.json` API). + Fulltext, + /// Match the regex against package names. Tokens are split on whitespace + /// and joined as `(?:t1|t2|...)`; callers must pre-quote regex metachars. + Name, + /// Match the regex against vendor names. Result rows have only `name` + /// populated (the vendor part). + Vendor, +} + /// One name-keyed lookup against a repository. /// /// Matches the `$packageNameMap` argument of Composer's `loadPackages`. The @@ -65,6 +82,22 @@ pub trait Repository: Send + Sync { /// Look up every version of every queried name this repo knows about. async fn load_packages(&self, queries: &[PackageQuery<'_>]) -> anyhow::Result<LoadResult>; + + /// Search this repository. + /// + /// The default returns an empty result so repositories that don't + /// participate in search (e.g. inline / VCS repos that only resolve + /// known names) can opt out. Mirrors Composer's + /// `RepositoryInterface::search` whose default behavior on + /// `ArrayRepository` walks the in-memory list. + async fn search( + &self, + _query: &str, + _mode: SearchMode, + _package_type: Option<&str>, + ) -> anyhow::Result<Vec<SearchResult>> { + Ok(Vec::new()) + } } /// Ordered list of repositories. Mirrors `Composer\Repository\RepositoryManager`. @@ -140,4 +173,22 @@ impl RepositorySet { Ok(packages) } + + /// Fan-out search across every repository, concatenating results in + /// priority order. Mirrors Composer's + /// `CompositeRepository::search` which `array_merge`s per-repo results + /// without de-duplication. + pub async fn search( + &self, + query: &str, + mode: SearchMode, + package_type: Option<&str>, + ) -> anyhow::Result<Vec<SearchResult>> { + let mut all = Vec::new(); + for repo in &self.repos { + let mut hits = repo.search(query, mode, package_type).await?; + all.append(&mut hits); + } + Ok(all) + } } |
