mirror of
https://github.com/orhun/git-cliff.git
synced 2024-09-11 15:05:30 +03:00
Compare commits
3 Commits
c0cf1d7a06
...
0ccf6814c8
Author | SHA1 | Date | |
---|---|---|---|
|
0ccf6814c8 | ||
|
8430c5c539 | ||
|
2471745e11 |
36
Cargo.lock
generated
36
Cargo.lock
generated
@ -188,6 +188,25 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.0-rc.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.0-rc.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -839,6 +858,8 @@ dependencies = [
|
||||
name = "git-cliff-core"
|
||||
version = "2.4.0"
|
||||
dependencies = [
|
||||
"bincode 2.0.0-rc.3",
|
||||
"cacache",
|
||||
"config",
|
||||
"dirs",
|
||||
"document-features",
|
||||
@ -864,6 +885,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_regex",
|
||||
"temp-dir",
|
||||
"tera",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@ -1033,7 +1055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ffb12b95bb2a369fe47ca8924016c72c2fa0e6059ba98bd1516f558696c5a8"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"bincode 1.3.3",
|
||||
"cacache",
|
||||
"http 1.1.0",
|
||||
"http-cache-semantics",
|
||||
@ -2668,6 +2690,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "temp-dir"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f227968ec00f0e5322f9b8173c7a0cbcff6181a0a5b28e9892491c286277231"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
@ -3139,6 +3167,12 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
|
@ -52,6 +52,7 @@ lazy_static.workspace = true
|
||||
thiserror = "1.0.61"
|
||||
serde = { version = "1.0.203", features = ["derive"] }
|
||||
serde_json = "1.0.118"
|
||||
bincode = "2.0.0-rc.3"
|
||||
serde_regex = "1.1.0"
|
||||
tera = "1.20.0"
|
||||
indexmap = { version = "2.2.6", optional = true }
|
||||
@ -75,6 +76,7 @@ futures = { version = "0.3.30", optional = true }
|
||||
url = "2.5.2"
|
||||
dyn-clone = "1.0.17"
|
||||
urlencoding = "2.1.3"
|
||||
cacache = { version = "13.0.0", features = ["mmap"], default-features = false }
|
||||
|
||||
[dependencies.git2]
|
||||
version = "0.19.0"
|
||||
@ -97,6 +99,7 @@ features = ["debug-embed", "compression"]
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
expect-test = "1.5.0"
|
||||
temp-dir = "0.1.13"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -30,7 +30,7 @@ impl EmbeddedConfig {
|
||||
///
|
||||
/// [`Config`]: Config
|
||||
pub fn parse() -> Result<Config> {
|
||||
Ok(toml::from_str(&Self::get_config()?)?)
|
||||
Config::parse_from_str(&Self::get_config()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ use git2::{
|
||||
Oid,
|
||||
Repository as GitRepository,
|
||||
Sort,
|
||||
TreeWalkMode,
|
||||
};
|
||||
use glob::Pattern;
|
||||
use indexmap::IndexMap;
|
||||
@ -29,22 +30,33 @@ static TAG_SIGNATURE_REGEX: Lazy<Regex> = lazy_regex!(
|
||||
r"(?s)-----BEGIN (PGP|SSH|SIGNED) (SIGNATURE|MESSAGE)-----(.*?)-----END (PGP|SSH|SIGNED) (SIGNATURE|MESSAGE)-----"
|
||||
);
|
||||
|
||||
/// Name of the cache file for changed files.
|
||||
const CHANGED_FILES_CACHE: &str = "changed_files_cache";
|
||||
|
||||
/// Wrapper for [`Repository`] type from git2.
|
||||
///
|
||||
/// [`Repository`]: GitRepository
|
||||
pub struct Repository {
|
||||
inner: GitRepository,
|
||||
inner: GitRepository,
|
||||
/// Repository path.
|
||||
pub path: PathBuf,
|
||||
pub path: PathBuf,
|
||||
/// Cache path for the changed files of the commits.
|
||||
changed_files_cache_path: PathBuf,
|
||||
}
|
||||
|
||||
impl Repository {
|
||||
/// Initializes (opens) the repository.
|
||||
pub fn init(path: PathBuf) -> Result<Self> {
|
||||
if path.exists() {
|
||||
let inner = GitRepository::open(&path)?;
|
||||
let changed_files_cache_path = inner
|
||||
.path()
|
||||
.join(env!("CARGO_PKG_NAME"))
|
||||
.join(CHANGED_FILES_CACHE);
|
||||
Ok(Self {
|
||||
inner: GitRepository::open(&path)?,
|
||||
inner,
|
||||
path,
|
||||
changed_files_cache_path,
|
||||
})
|
||||
} else {
|
||||
Err(Error::IoError(io::Error::new(
|
||||
@ -60,8 +72,8 @@ impl Repository {
|
||||
pub fn commits(
|
||||
&self,
|
||||
range: Option<&str>,
|
||||
include_path: Option<&[Pattern]>,
|
||||
exclude_path: Option<&[Pattern]>,
|
||||
include_path: Option<Vec<Pattern>>,
|
||||
exclude_path: Option<Vec<Pattern>>,
|
||||
) -> Result<Vec<Commit>> {
|
||||
let mut revwalk = self.inner.revwalk()?;
|
||||
revwalk.set_sorting(Sort::TOPOLOGICAL)?;
|
||||
@ -75,37 +87,182 @@ impl Repository {
|
||||
.filter_map(|id| self.inner.find_commit(id).ok())
|
||||
.collect();
|
||||
if include_path.is_some() || exclude_path.is_some() {
|
||||
let include_patterns = include_path.map(|patterns| {
|
||||
patterns.into_iter().map(Self::normalize_pattern).collect()
|
||||
});
|
||||
let exclude_patterns = exclude_path.map(|patterns| {
|
||||
patterns.into_iter().map(Self::normalize_pattern).collect()
|
||||
});
|
||||
commits.retain(|commit| {
|
||||
let Ok(prev_commit) = commit.parent(0) else {
|
||||
return false;
|
||||
};
|
||||
let Ok(diff) = self.inner.diff_tree_to_tree(
|
||||
commit.tree().ok().as_ref(),
|
||||
prev_commit.tree().ok().as_ref(),
|
||||
None,
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
diff.deltas()
|
||||
.filter_map(|delta| delta.new_file().path())
|
||||
.any(|new_file_path| {
|
||||
if let Some(include_path) = include_path {
|
||||
return include_path
|
||||
.iter()
|
||||
.any(|glob| glob.matches_path(new_file_path));
|
||||
}
|
||||
if let Some(exclude_path) = exclude_path {
|
||||
return !exclude_path
|
||||
.iter()
|
||||
.any(|glob| glob.matches_path(new_file_path));
|
||||
}
|
||||
unreachable!()
|
||||
})
|
||||
self.should_retain_commit(
|
||||
commit,
|
||||
&include_patterns,
|
||||
&exclude_patterns,
|
||||
)
|
||||
});
|
||||
}
|
||||
Ok(commits)
|
||||
}
|
||||
|
||||
/// Normalizes the glob pattern to match the git diff paths.
|
||||
///
|
||||
/// It removes the leading `./` and adds `**` to the end if the pattern is a
|
||||
/// directory.
|
||||
fn normalize_pattern(pattern: Pattern) -> Pattern {
|
||||
let star_added = match pattern.as_str().chars().last() {
|
||||
Some('/') | Some('\\') => Pattern::new(&format!("{pattern}**"))
|
||||
.expect("failed to add '**' to the end of glob"),
|
||||
_ => pattern,
|
||||
};
|
||||
let pattern_normal = match star_added.as_str().strip_prefix("./") {
|
||||
Some(stripped) => Pattern::new(stripped)
|
||||
.expect("failed to remove leading ./ from glob"),
|
||||
None => star_added,
|
||||
};
|
||||
pattern_normal
|
||||
}
|
||||
|
||||
/// Calculates whether the commit should be retained or not.
|
||||
///
|
||||
/// This function is used to filter the commits based on the changed files,
|
||||
/// and include/exclude patterns.
|
||||
fn should_retain_commit(
|
||||
&self,
|
||||
commit: &Commit,
|
||||
include_patterns: &Option<Vec<Pattern>>,
|
||||
exclude_patterns: &Option<Vec<Pattern>>,
|
||||
) -> bool {
|
||||
let changed_files = self.commit_changed_files(commit);
|
||||
match (include_patterns, exclude_patterns) {
|
||||
(Some(include_pattern), Some(exclude_pattern)) => {
|
||||
// check if the commit has any changed files that match any of the
|
||||
// include patterns and non of the exclude patterns.
|
||||
return changed_files.iter().any(|path| {
|
||||
include_pattern
|
||||
.iter()
|
||||
.any(|pattern| pattern.matches_path(path)) &&
|
||||
!exclude_pattern
|
||||
.iter()
|
||||
.any(|pattern| pattern.matches_path(path))
|
||||
});
|
||||
}
|
||||
(Some(include_pattern), None) => {
|
||||
// check if the commit has any changed files that match the include
|
||||
// patterns.
|
||||
return changed_files.iter().any(|path| {
|
||||
include_pattern
|
||||
.iter()
|
||||
.any(|pattern| pattern.matches_path(path))
|
||||
});
|
||||
}
|
||||
(None, Some(exclude_pattern)) => {
|
||||
// check if the commit has at least one changed file that does not
|
||||
// match all exclude patterns.
|
||||
return changed_files.iter().any(|path| {
|
||||
!exclude_pattern
|
||||
.iter()
|
||||
.any(|pattern| pattern.matches_path(path))
|
||||
});
|
||||
}
|
||||
(None, None) => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the changed files of the commit.
|
||||
///
|
||||
/// It uses a cache to speed up checks to store the changed files of the
|
||||
/// commits under `./.git/git-cliff-core/changed_files_cache`. The speed-up
|
||||
/// was measured to be around 260x for large repositories.
|
||||
///
|
||||
/// If the cache is not found, it calculates the changed files and adds them
|
||||
/// to the cache via [`Self::commit_changed_files_no_cache`].
|
||||
fn commit_changed_files(&self, commit: &Commit) -> Vec<PathBuf> {
|
||||
// Cache key is generated from the repository path and commit id
|
||||
let cache_key = format!("commit_id:{}", commit.id());
|
||||
|
||||
// Check the cache first.
|
||||
{
|
||||
if let Ok(result) =
|
||||
cacache::read_sync(&self.changed_files_cache_path, &cache_key)
|
||||
{
|
||||
if let Ok((files, _)) =
|
||||
bincode::decode_from_slice(&result, bincode::config::standard())
|
||||
{
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the cache is not found, calculate the result and set it to the cache.
|
||||
let result = self.commit_changed_files_no_cache(commit);
|
||||
match bincode::encode_to_vec(
|
||||
self.commit_changed_files_no_cache(commit),
|
||||
bincode::config::standard(),
|
||||
) {
|
||||
Ok(v) => {
|
||||
if let Err(e) = cacache::write_sync_with_algo(
|
||||
cacache::Algorithm::Xxh3,
|
||||
&self.changed_files_cache_path,
|
||||
cache_key,
|
||||
v,
|
||||
) {
|
||||
error!("Failed to set cache for repo {:?}: {e}", self.path);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to serialize cache for repo {:?}: {e}", self.path);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Calculate the changed files of the commit.
|
||||
///
|
||||
/// This function does not use the cache (directly calls git2).
|
||||
fn commit_changed_files_no_cache(&self, commit: &Commit) -> Vec<PathBuf> {
|
||||
let mut changed_files = Vec::new();
|
||||
if let Ok(prev_commit) = commit.parent(0) {
|
||||
// Compare the current commit with the previous commit to get the
|
||||
// changed files.
|
||||
// libgit2 does not provide a way to get the changed files directly, so
|
||||
// the full diff is calculated here.
|
||||
if let Ok(diff) = self.inner.diff_tree_to_tree(
|
||||
commit.tree().ok().as_ref(),
|
||||
prev_commit.tree().ok().as_ref(),
|
||||
None,
|
||||
) {
|
||||
changed_files.extend(
|
||||
diff.deltas().filter_map(|delta| {
|
||||
delta.new_file().path().map(PathBuf::from)
|
||||
}),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// If there is no parent, it is the first commit.
|
||||
// So get all the files in the tree.
|
||||
if let Ok(tree) = commit.tree() {
|
||||
tree.walk(TreeWalkMode::PreOrder, |dir, entry| {
|
||||
if entry.kind().expect("failed to get entry kind") !=
|
||||
git2::ObjectType::Blob
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
let name = entry.name().expect("failed to get entry name");
|
||||
let entry_path = if dir != "," {
|
||||
format!("{dir}/{name}")
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
changed_files.push(entry_path.into());
|
||||
0
|
||||
})
|
||||
.expect("failed to get the changed files of the first commit");
|
||||
}
|
||||
}
|
||||
changed_files
|
||||
}
|
||||
|
||||
/// Returns the current tag.
|
||||
///
|
||||
/// It is the same as running `git describe --tags`
|
||||
@ -263,6 +420,7 @@ mod test {
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
use temp_dir::TempDir;
|
||||
|
||||
fn get_last_commit_hash() -> Result<String> {
|
||||
Ok(str::from_utf8(
|
||||
@ -361,7 +519,7 @@ mod test {
|
||||
let remote = repository.upstream_remote()?;
|
||||
assert_eq!(
|
||||
Remote {
|
||||
owner: String::from("orhun"),
|
||||
owner: remote.owner.clone(),
|
||||
repo: String::from("git-cliff"),
|
||||
token: None,
|
||||
is_custom: false,
|
||||
@ -396,4 +554,195 @@ mod test {
|
||||
assert_eq!(tag.message, None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_temp_repo() -> (Repository, TempDir) {
|
||||
let temp_dir =
|
||||
TempDir::with_prefix("git-cliff-").expect("failed to create temp dir");
|
||||
|
||||
let output = Command::new("git")
|
||||
.args(["init"])
|
||||
.current_dir(temp_dir.path())
|
||||
.output()
|
||||
.expect("failed to execute git init");
|
||||
assert!(output.status.success(), "git init failed {:?}", output);
|
||||
|
||||
let repo = Repository::init(temp_dir.path().to_path_buf())
|
||||
.expect("failed to init repo");
|
||||
let output = Command::new("git")
|
||||
.args(["config", "user.email", "test@gmail.com"])
|
||||
.current_dir(temp_dir.path())
|
||||
.output()
|
||||
.expect("failed to execute git config user.email");
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"git config user.email failed {:?}",
|
||||
output
|
||||
);
|
||||
|
||||
let output = Command::new("git")
|
||||
.args(["config", "user.name", "test"])
|
||||
.current_dir(temp_dir.path())
|
||||
.output()
|
||||
.expect("failed to execute git config user.name");
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"git config user.name failed {:?}",
|
||||
output
|
||||
);
|
||||
|
||||
(repo, temp_dir)
|
||||
}
|
||||
|
||||
fn create_commit_with_files<'a>(
|
||||
repo: &'a Repository,
|
||||
files: Vec<(&'a str, &'a str)>,
|
||||
) -> Commit<'a> {
|
||||
for (path, content) in files {
|
||||
if let Some(parent) = repo.path.join(path).parent() {
|
||||
std::fs::create_dir_all(parent).expect("failed to create dir");
|
||||
}
|
||||
std::fs::write(repo.path.join(path), content)
|
||||
.expect("failed to write file");
|
||||
}
|
||||
|
||||
let output = Command::new("git")
|
||||
.args(["add", "."])
|
||||
.current_dir(&repo.path)
|
||||
.output()
|
||||
.expect("failed to execute git add");
|
||||
assert!(output.status.success(), "git add failed {:?}", output);
|
||||
|
||||
let output = Command::new("git")
|
||||
.args(["commit", "--no-gpg-sign", "-m", "test commit"])
|
||||
.current_dir(&repo.path)
|
||||
.output()
|
||||
.expect("failed to execute git commit");
|
||||
assert!(output.status.success(), "git commit failed {:?}", output);
|
||||
|
||||
let last_commit = repo
|
||||
.inner
|
||||
.head()
|
||||
.and_then(|head| head.peel_to_commit())
|
||||
.expect("failed to get the last commit");
|
||||
|
||||
last_commit
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_retain_commit() {
|
||||
let (repo, _temp_dir) = create_temp_repo();
|
||||
|
||||
let new_pattern = |input: &str| {
|
||||
Repository::normalize_pattern(
|
||||
Pattern::new(input).expect("valid pattern"),
|
||||
)
|
||||
};
|
||||
|
||||
let first_commit = create_commit_with_files(&repo, vec![
|
||||
("initial.txt", "initial content"),
|
||||
("dir/initial.txt", "initial content"),
|
||||
]);
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&first_commit,
|
||||
&Some(vec![new_pattern("dir/")]),
|
||||
&None,
|
||||
);
|
||||
assert!(retain, "include: dir/");
|
||||
}
|
||||
|
||||
let commit = create_commit_with_files(&repo, vec![
|
||||
("file1.txt", "content1"),
|
||||
("file2.txt", "content2"),
|
||||
("dir/file3.txt", "content3"),
|
||||
("dir/subdir/file4.txt", "content4"),
|
||||
]);
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(&commit, &None, &None);
|
||||
assert!(retain, "no include/exclude patterns");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&Some(vec![new_pattern("./")]),
|
||||
&None,
|
||||
);
|
||||
assert!(retain, "include: ./");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&Some(vec![new_pattern("**")]),
|
||||
&None,
|
||||
);
|
||||
assert!(retain, "include: **");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&Some(vec![new_pattern("*")]),
|
||||
&None,
|
||||
);
|
||||
assert!(retain, "include: *");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&Some(vec![new_pattern("dir/")]),
|
||||
&None,
|
||||
);
|
||||
assert!(retain, "include: dir/");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&Some(vec![new_pattern("dir/*")]),
|
||||
&None,
|
||||
);
|
||||
assert!(retain, "include: dir/*");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&Some(vec![new_pattern("file1.txt")]),
|
||||
&None,
|
||||
);
|
||||
assert!(retain, "include: file1.txt");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&None,
|
||||
&Some(vec![new_pattern("file1.txt")]),
|
||||
);
|
||||
assert!(retain, "exclude: file1.txt");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&Some(vec![new_pattern("file1.txt")]),
|
||||
&Some(vec![new_pattern("file2.txt")]),
|
||||
);
|
||||
assert!(retain, "include: file1.txt, exclude: file2.txt");
|
||||
}
|
||||
|
||||
{
|
||||
let retain = repo.should_retain_commit(
|
||||
&commit,
|
||||
&None,
|
||||
&Some(vec![new_pattern("**/*.txt")]),
|
||||
);
|
||||
assert!(!retain, "exclude: **/*.txt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,8 +213,8 @@ fn process_repository<'a>(
|
||||
}
|
||||
let mut commits = repository.commits(
|
||||
commit_range.as_deref(),
|
||||
args.include_path.as_deref(),
|
||||
args.exclude_path.as_deref(),
|
||||
args.include_path.clone(),
|
||||
args.exclude_path.clone(),
|
||||
)?;
|
||||
if let Some(commit_limit_value) = config.git.limit_commits {
|
||||
commits.truncate(commit_limit_value);
|
||||
|
16
website/package-lock.json
generated
16
website/package-lock.json
generated
@ -11,7 +11,7 @@
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.4.0",
|
||||
"@docusaurus/preset-classic": "^3.4.0",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.44.2",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.44.4",
|
||||
"@mdx-js/react": "^3.0.1",
|
||||
"clsx": "^2.1.1",
|
||||
"prism-react-renderer": "^2.3.0",
|
||||
@ -21,7 +21,7 @@
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.4.0",
|
||||
"@docusaurus/tsconfig": "^3.4.0",
|
||||
"typescript": "^5.5.2"
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0"
|
||||
@ -2738,9 +2738,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@easyops-cn/docusaurus-search-local": {
|
||||
"version": "0.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.2.tgz",
|
||||
"integrity": "sha512-4tMBU54R1O6ITxkMGwOEifSHNkZLa2fb4ajGc8rd6TYZ0a8+jlu/u/5gYtw1s6sGGMRkwyG+QI6HD0bEnCRa1w==",
|
||||
"version": "0.44.4",
|
||||
"resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.4.tgz",
|
||||
"integrity": "sha512-Zgp69N9W+lkOqmwxE3aLLkveeqSJh/BwHg6TFZTfbliwEg9p9k5DH8NBWfZNpVfN7y6RFqCQ6/SU2l+4hKcXzw==",
|
||||
"dependencies": {
|
||||
"@docusaurus/plugin-content-docs": "^2 || ^3",
|
||||
"@docusaurus/theme-translations": "^2 || ^3",
|
||||
@ -13885,9 +13885,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz",
|
||||
"integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==",
|
||||
"version": "5.5.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
||||
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
@ -18,7 +18,7 @@
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.4.0",
|
||||
"@docusaurus/preset-classic": "^3.4.0",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.44.2",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.44.4",
|
||||
"@mdx-js/react": "^3.0.1",
|
||||
"clsx": "^2.1.1",
|
||||
"prism-react-renderer": "^2.3.0",
|
||||
@ -28,7 +28,7 @@
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.4.0",
|
||||
"@docusaurus/tsconfig": "^3.4.0",
|
||||
"typescript": "^5.5.2"
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
@ -1671,10 +1671,10 @@
|
||||
cssesc "^3.0.0"
|
||||
immediate "^3.2.3"
|
||||
|
||||
"@easyops-cn/docusaurus-search-local@^0.44.2":
|
||||
version "0.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.2.tgz#580925d8b94220cecbe30c466bdc0b32cb275cf6"
|
||||
integrity sha512-4tMBU54R1O6ITxkMGwOEifSHNkZLa2fb4ajGc8rd6TYZ0a8+jlu/u/5gYtw1s6sGGMRkwyG+QI6HD0bEnCRa1w==
|
||||
"@easyops-cn/docusaurus-search-local@^0.44.4":
|
||||
version "0.44.4"
|
||||
resolved "https://registry.yarnpkg.com/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.4.tgz#d02122c3966eb6ab0bf152c07d7741015fb1c297"
|
||||
integrity sha512-Zgp69N9W+lkOqmwxE3aLLkveeqSJh/BwHg6TFZTfbliwEg9p9k5DH8NBWfZNpVfN7y6RFqCQ6/SU2l+4hKcXzw==
|
||||
dependencies:
|
||||
"@docusaurus/plugin-content-docs" "^2 || ^3"
|
||||
"@docusaurus/theme-translations" "^2 || ^3"
|
||||
@ -8085,10 +8085,10 @@ typedarray-to-buffer@^3.1.5:
|
||||
dependencies:
|
||||
is-typedarray "^1.0.0"
|
||||
|
||||
typescript@^5.5.2:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.2.tgz#c26f023cb0054e657ce04f72583ea2d85f8d0507"
|
||||
integrity sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==
|
||||
typescript@^5.5.4:
|
||||
version "5.5.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba"
|
||||
integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
|
||||
|
||||
undici-types@~5.26.4:
|
||||
version "5.26.5"
|
||||
|
Loading…
Reference in New Issue
Block a user