1
1
mirror of https://github.com/orhun/git-cliff.git synced 2024-09-11 15:05:30 +03:00

Compare commits

...

3 Commits

Author SHA1 Message Date
dependabot[bot]
f8612c3451
chore(deps): bump the patch group across 1 directory with 2 updates
Bumps the patch group with 2 updates in the /website directory: [@easyops-cn/docusaurus-search-local](https://github.com/easyops-cn/docusaurus-search-local/tree/HEAD/packages/docusaurus-search-local) and [typescript](https://github.com/Microsoft/TypeScript).


Updates `@easyops-cn/docusaurus-search-local` from 0.44.2 to 0.44.4
- [Release notes](https://github.com/easyops-cn/docusaurus-search-local/releases)
- [Commits](https://github.com/easyops-cn/docusaurus-search-local/commits/v0.44.4/packages/docusaurus-search-local)

Updates `typescript` from 5.5.2 to 5.5.3
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.5.2...v5.5.3)

---
updated-dependencies:
- dependency-name: "@easyops-cn/docusaurus-search-local"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 22:25:03 +00:00
Orhun Parmaksız
4b33e7e986
feat(remote): activate integration if remote is set manually (#782) 2024-08-04 22:35:32 +03:00
DaniPopes
4b0c0eb09a
refactor(lib): clean up some code (#709)
* refactor: clean up some code

* Update git-cliff/src/lib.rs

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* review

* fmt

* fix: read before opening the file to prepend

* style: update formatting

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-04 00:05:26 +03:00
7 changed files with 187 additions and 181 deletions

View File

@ -206,9 +206,9 @@ impl<'a> Changelog<'a> {
#[cfg(feature = "github")]
fn get_github_metadata(&self) -> Result<crate::remote::RemoteMetadata> {
use crate::remote::github;
if self
.body_template
.contains_variable(github::TEMPLATE_VARIABLES) ||
if self.config.remote.github.is_custom ||
self.body_template
.contains_variable(github::TEMPLATE_VARIABLES) ||
self.footer_template
.as_ref()
.map(|v| v.contains_variable(github::TEMPLATE_VARIABLES))
@ -262,9 +262,9 @@ impl<'a> Changelog<'a> {
#[cfg(feature = "gitlab")]
fn get_gitlab_metadata(&self) -> Result<crate::remote::RemoteMetadata> {
use crate::remote::gitlab;
if self
.body_template
.contains_variable(gitlab::TEMPLATE_VARIABLES) ||
if self.config.remote.gitlab.is_custom ||
self.body_template
.contains_variable(gitlab::TEMPLATE_VARIABLES) ||
self.footer_template
.as_ref()
.map(|v| v.contains_variable(gitlab::TEMPLATE_VARIABLES))
@ -326,9 +326,9 @@ impl<'a> Changelog<'a> {
#[cfg(feature = "gitea")]
fn get_gitea_metadata(&self) -> Result<crate::remote::RemoteMetadata> {
use crate::remote::gitea;
if self
.body_template
.contains_variable(gitea::TEMPLATE_VARIABLES) ||
if self.config.remote.gitea.is_custom ||
self.body_template
.contains_variable(gitea::TEMPLATE_VARIABLES) ||
self.footer_template
.as_ref()
.map(|v| v.contains_variable(gitea::TEMPLATE_VARIABLES))
@ -379,9 +379,9 @@ impl<'a> Changelog<'a> {
#[cfg(feature = "bitbucket")]
fn get_bitbucket_metadata(&self) -> Result<crate::remote::RemoteMetadata> {
use crate::remote::bitbucket;
if self
.body_template
.contains_variable(bitbucket::TEMPLATE_VARIABLES) ||
if self.config.remote.bitbucket.is_custom ||
self.body_template
.contains_variable(bitbucket::TEMPLATE_VARIABLES) ||
self.footer_template
.as_ref()
.map(|v| v.contains_variable(bitbucket::TEMPLATE_VARIABLES))
@ -499,7 +499,7 @@ impl<'a> Changelog<'a> {
}
/// Generates the changelog and writes it to the given output.
pub fn generate<W: Write>(&self, out: &mut W) -> Result<()> {
pub fn generate<W: Write + ?Sized>(&self, out: &mut W) -> Result<()> {
debug!("Generating changelog...");
let postprocessors = self
.config
@ -567,7 +567,7 @@ impl<'a> Changelog<'a> {
}
/// Generates a changelog and prepends it to the given changelog.
pub fn prepend<W: Write>(
pub fn prepend<W: Write + ?Sized>(
&self,
mut changelog: String,
out: &mut W,
@ -582,7 +582,7 @@ impl<'a> Changelog<'a> {
}
/// Prints the changelog context to the given output.
pub fn write_context<W: Write>(&self, out: &mut W) -> Result<()> {
pub fn write_context<W: Write + ?Sized>(&self, out: &mut W) -> Result<()> {
let output = Releases {
releases: &self.releases,
}
@ -791,24 +791,28 @@ mod test {
},
remote: RemoteConfig {
github: Remote {
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
is_custom: false,
},
gitlab: Remote {
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
is_custom: false,
},
gitea: Remote {
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
is_custom: false,
},
bitbucket: Remote {
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
owner: String::from("coolguy"),
repo: String::from("awesome"),
token: None,
is_custom: false,
},
},
bump: Bump::default(),

View File

@ -138,12 +138,20 @@ pub struct RemoteConfig {
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Remote {
/// Owner of the remote.
pub owner: String,
pub owner: String,
/// Repository name.
pub repo: String,
pub repo: String,
/// Access token.
#[serde(skip_serializing)]
pub token: Option<SecretString>,
pub token: Option<SecretString>,
/// Whether if the remote is set manually.
#[serde(skip_deserializing, default = "default_true")]
pub is_custom: bool,
}
/// Returns `true` for serde's `default` attribute.
fn default_true() -> bool {
true
}
impl fmt::Display for Remote {
@ -162,9 +170,10 @@ impl Remote {
/// Constructs a new instance.
pub fn new<S: Into<String>>(owner: S, repo: S) -> Self {
Self {
owner: owner.into(),
repo: repo.into(),
token: None,
owner: owner.into(),
repo: repo.into(),
token: None,
is_custom: false,
}
}

View File

@ -59,14 +59,14 @@ impl Repository {
/// Sorts the commits by their time.
pub fn commits(
&self,
range: Option<String>,
include_path: Option<Vec<Pattern>>,
exclude_path: Option<Vec<Pattern>>,
range: Option<&str>,
include_path: Option<&[Pattern]>,
exclude_path: Option<&[Pattern]>,
) -> Result<Vec<Commit>> {
let mut revwalk = self.inner.revwalk()?;
revwalk.set_sorting(Sort::TOPOLOGICAL)?;
if let Some(range) = range {
revwalk.push_range(&range)?;
revwalk.push_range(range)?;
} else {
revwalk.push_head()?;
}
@ -76,31 +76,31 @@ impl Repository {
.collect();
if include_path.is_some() || exclude_path.is_some() {
commits.retain(|commit| {
if let Ok(prev_commit) = commit.parent(0) {
if let Ok(diff) = self.inner.diff_tree_to_tree(
commit.tree().ok().as_ref(),
prev_commit.tree().ok().as_ref(),
None,
) {
return diff
.deltas()
.filter_map(|delta| delta.new_file().path())
.any(|new_file_path| {
if let Some(include_path) = &include_path {
include_path
.iter()
.any(|glob| glob.matches_path(new_file_path))
} else if let Some(exclude_path) = &exclude_path {
!exclude_path
.iter()
.any(|glob| glob.matches_path(new_file_path))
} else {
false
}
});
}
}
false
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!()
})
});
}
Ok(commits)
@ -244,9 +244,10 @@ impl Repository {
(segments.get(1), segments.first())
{
return Ok(Remote {
owner: owner.to_string(),
repo: repo.trim_end_matches(".git").to_string(),
token: None,
owner: owner.to_string(),
repo: repo.trim_end_matches(".git").to_string(),
token: None,
is_custom: false,
});
}
}
@ -360,9 +361,10 @@ mod test {
let remote = repository.upstream_remote()?;
assert_eq!(
Remote {
owner: String::from("orhun"),
repo: String::from("git-cliff"),
token: None,
owner: String::from("orhun"),
repo: String::from("git-cliff"),
token: None,
is_custom: false,
},
remote
);

View File

@ -45,11 +45,8 @@ use std::fs::{
self,
File,
};
use std::io::{
self,
Write,
};
use std::path::PathBuf;
use std::io;
use std::path::Path;
use std::time::{
SystemTime,
UNIX_EPOCH,
@ -89,31 +86,28 @@ fn process_repository<'a>(
let mut tags = repository.tags(&config.git.tag_pattern, args.topo_order)?;
let skip_regex = config.git.skip_tags.as_ref();
let ignore_regex = config.git.ignore_tags.as_ref();
tags = tags
.into_iter()
.filter(|(_, tag)| {
let name = &tag.name;
tags.retain(|_, tag| {
let name = &tag.name;
// Keep skip tags to drop commits in the later stage.
let skip = skip_regex.map(|r| r.is_match(name)).unwrap_or_default();
// Keep skip tags to drop commits in the later stage.
let skip = skip_regex.is_some_and(|r| r.is_match(name));
if skip {
return true;
}
let ignore = ignore_regex
.map(|r| {
if r.as_str().trim().is_empty() {
return false;
}
let ignore = ignore_regex.is_some_and(|r| {
if r.as_str().trim().is_empty() {
return false;
}
let ignore_tag = r.is_match(name);
if ignore_tag {
trace!("Ignoring release: {}", name)
}
ignore_tag
})
.unwrap_or_default();
skip || !ignore
})
.collect();
let ignore_tag = r.is_match(name);
if ignore_tag {
trace!("Ignoring release: {}", name)
}
ignore_tag
});
!ignore
});
if !config.remote.github.is_set() {
match repository.upstream_remote() {
@ -121,6 +115,7 @@ fn process_repository<'a>(
debug!("No GitHub remote is set, using remote: {}", remote);
config.remote.github.owner = remote.owner;
config.remote.github.repo = remote.repo;
config.remote.github.is_custom = remote.is_custom;
}
Err(e) => {
debug!("Failed to get remote from GitHub repository: {:?}", e);
@ -132,6 +127,7 @@ fn process_repository<'a>(
debug!("No GitLab remote is set, using remote: {}", remote);
config.remote.gitlab.owner = remote.owner;
config.remote.gitlab.repo = remote.repo;
config.remote.gitlab.is_custom = remote.is_custom;
}
Err(e) => {
debug!("Failed to get remote from GitLab repository: {:?}", e);
@ -143,6 +139,7 @@ fn process_repository<'a>(
debug!("No Gitea remote is set, using remote: {}", remote);
config.remote.gitea.owner = remote.owner;
config.remote.gitea.repo = remote.repo;
config.remote.gitea.is_custom = remote.is_custom;
}
Err(e) => {
debug!("Failed to get remote from Gitea repository: {:?}", e);
@ -154,6 +151,7 @@ fn process_repository<'a>(
debug!("No Bitbucket remote is set, using remote: {}", remote);
config.remote.bitbucket.owner = remote.owner;
config.remote.bitbucket.repo = remote.repo;
config.remote.bitbucket.is_custom = remote.is_custom;
}
Err(e) => {
debug!("Failed to get remote from Bitbucket repository: {:?}", e);
@ -214,14 +212,12 @@ fn process_repository<'a>(
}
}
let mut commits = repository.commits(
commit_range,
args.include_path.clone(),
args.exclude_path.clone(),
commit_range.as_deref(),
args.include_path.as_deref(),
args.exclude_path.as_deref(),
)?;
if let Some(commit_limit_value) = config.git.limit_commits {
commits = commits
.drain(..commits.len().min(commit_limit_value))
.collect();
commits.truncate(commit_limit_value);
}
// Update tags.
@ -240,27 +236,19 @@ fn process_repository<'a>(
// Process releases.
let mut releases = vec![Release::default()];
let mut release_index = 0;
let mut previous_release = Release::default();
let mut first_processed_tag = None;
for git_commit in commits.iter().rev() {
let release = releases.last_mut().unwrap();
let commit = Commit::from(git_commit);
let commit_id = commit.id.to_string();
releases[release_index].repository =
Some(repository.path.to_string_lossy().to_string());
if args.sort == Sort::Newest {
releases[release_index].commits.insert(0, commit);
} else {
releases[release_index].commits.push(commit);
}
release.commits.push(commit);
release.repository = Some(repository.path.to_string_lossy().into_owned());
if let Some(tag) = tags.get(&commit_id) {
let tag_name = &tag.name;
releases[release_index].version = Some(tag_name.clone());
releases[release_index].message = tag.message.clone();
releases[release_index].commit_id = Some(commit_id);
releases[release_index].timestamp = if args.tag == Some(tag_name.clone())
{
release.version = Some(tag.name.to_string());
release.message = tag.message.clone();
release.commit_id = Some(commit_id);
release.timestamp = if args.tag.as_deref() == Some(tag.name.as_str()) {
SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_secs()
@ -272,27 +260,32 @@ fn process_repository<'a>(
first_processed_tag = Some(tag);
}
previous_release.previous = None;
releases[release_index].previous = Some(Box::new(previous_release));
previous_release = releases[release_index].clone();
release.previous = Some(Box::new(previous_release));
previous_release = release.clone();
releases.push(Release::default());
release_index += 1;
}
}
if release_index > 0 {
debug_assert!(!releases.is_empty());
if releases.len() > 1 {
previous_release.previous = None;
releases[release_index].previous = Some(Box::new(previous_release));
releases.last_mut().unwrap().previous = Some(Box::new(previous_release));
}
if args.sort == Sort::Newest {
for release in &mut releases {
release.commits.reverse();
}
}
// Add custom commit messages to the latest release.
if let Some(custom_commits) = &args.with_commit {
if let Some(latest_release) = releases.iter_mut().last() {
custom_commits.iter().for_each(|message| {
latest_release
.commits
.push(Commit::from(message.to_string()))
});
}
releases
.last_mut()
.unwrap()
.commits
.extend(custom_commits.iter().cloned().map(Commit::from));
}
// Set custom message for the latest release.
@ -303,12 +296,11 @@ fn process_repository<'a>(
}
// Set the previous release if the first release does not have one set.
if !releases.is_empty() &&
releases
.first()
.and_then(|r| r.previous.as_ref())
.and_then(|p| p.version.as_ref())
.is_none()
if releases[0]
.previous
.as_ref()
.and_then(|p| p.version.as_ref())
.is_none()
{
// Get the previous tag of the first processed tag in the release loop.
let first_tag = first_processed_tag
@ -477,14 +469,22 @@ pub fn run(mut args: Opt) -> Result<()> {
if let Some(ref remote) = args.github_repo {
config.remote.github.owner = remote.0.owner.to_string();
config.remote.github.repo = remote.0.repo.to_string();
config.remote.github.is_custom = true;
}
if let Some(ref remote) = args.gitlab_repo {
config.remote.gitlab.owner = remote.0.owner.to_string();
config.remote.gitlab.repo = remote.0.repo.to_string();
config.remote.gitlab.is_custom = true;
}
if let Some(ref remote) = args.bitbucket_repo {
config.remote.bitbucket.owner = remote.0.owner.to_string();
config.remote.bitbucket.repo = remote.0.repo.to_string();
config.remote.bitbucket.is_custom = true;
}
if let Some(ref remote) = args.gitea_repo {
config.remote.gitea.owner = remote.0.owner.to_string();
config.remote.gitea.repo = remote.0.repo.to_string();
config.remote.gitea.is_custom = true;
}
if args.no_exec {
if let Some(ref mut preprocessors) = config.git.commit_preprocessors {
@ -553,6 +553,15 @@ pub fn run(mut args: Opt) -> Result<()> {
let mut changelog = Changelog::new(releases, &config)?;
// Print the result.
let mut out: Box<dyn io::Write> = if let Some(path) = &args.output {
if path == Path::new("-") {
Box::new(io::stdout())
} else {
Box::new(io::BufWriter::new(File::create(path)?))
}
} else {
Box::new(io::stdout())
};
if args.bump.is_some() || args.bumped_version {
let next_version = if let Some(next_version) = changelog.bump_version()? {
next_version
@ -565,40 +574,22 @@ pub fn run(mut args: Opt) -> Result<()> {
return Ok(());
};
if args.bumped_version {
if let Some(path) = args.output {
let mut output = File::create(path)?;
output.write_all(next_version.as_bytes())?;
} else {
println!("{next_version}");
}
writeln!(out, "{next_version}")?;
return Ok(());
}
}
if args.context {
return if let Some(path) = args.output {
let mut output = File::create(path)?;
changelog.write_context(&mut output)
} else {
changelog.write_context(&mut io::stdout())
};
changelog.write_context(&mut out)?;
return Ok(());
}
if let Some(ref path) = args.prepend {
changelog.prepend(fs::read_to_string(path)?, &mut File::create(path)?)?;
if let Some(path) = &args.prepend {
let changelog_before = fs::read_to_string(path)?;
let mut out = io::BufWriter::new(File::create(path)?);
changelog.prepend(changelog_before, &mut out)?;
}
if let Some(path) = args.output {
let mut output: Box<dyn Write> = if path == PathBuf::from("-") {
Box::new(io::stdout())
} else {
Box::new(File::create(path)?)
};
if args.context {
changelog.write_context(&mut output)
} else {
changelog.generate(&mut output)
}
} else if args.prepend.is_none() {
changelog.generate(&mut io::stdout())
} else {
Ok(())
if args.output.is_some() || args.prepend.is_none() {
changelog.generate(&mut out)?;
}
Ok(())
}

View File

@ -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"

View File

@ -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": [

View File

@ -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"