Remove download font scripts (#11317)

The fonts were added (by mistake) anyway, but they are rarely changed, and the scripts add unnecessary complexity.

This also fixes some post- #11287 problems.
This commit is contained in:
Adam Obuchowicz 2024-10-14 18:11:42 +02:00 committed by GitHub
parent 244effde0c
commit d1ee7fadce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 75 additions and 1522 deletions

View File

@ -1,5 +1,6 @@
# Build Artefacts
dist
mockDist
target
# Release body template should not be auto-formatted, as the word wrap does not really looks good in the GitHub UI.

34
Cargo.lock generated
View File

@ -1211,8 +1211,6 @@ dependencies = [
"dirs",
"enso-build-base",
"enso-build-macros-lib",
"enso-enso-font",
"enso-font",
"enso-install-config",
"futures",
"glob",
@ -1313,23 +1311,6 @@ dependencies = [
"serde",
]
[[package]]
name = "enso-enso-font"
version = "0.1.0"
dependencies = [
"enso-font",
"ide-ci",
"owned_ttf_parser",
]
[[package]]
name = "enso-font"
version = "0.1.0"
dependencies = [
"derive_more",
"owned_ttf_parser",
]
[[package]]
name = "enso-formatter"
version = "0.1.0"
@ -2858,15 +2839,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owned_ttf_parser"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e6affeb1632d6ff6a23d2cd40ffed138e82f1532571a26f527c8a284bb2fbb"
dependencies = [
"ttf-parser",
]
[[package]]
name = "parking"
version = "2.2.0"
@ -4349,12 +4321,6 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "ttf-parser"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
[[package]]
name = "tuikit"
version = "0.5.0"

6
app/gui/.gitignore vendored
View File

@ -26,11 +26,5 @@ mockDist
test-results/
playwright-report/
public/font-dejavu/
public/font-enso/
public/font-mplus1/
src/project-view/assets/font-dejavu.css
src/project-view/assets/font-enso.css
src/project-view/assets/font-mplus1.css
src/project-view/util/iconList.json
src/project-view/util/iconName.ts

View File

@ -29,11 +29,10 @@
"test-dev:unit": "vitest",
"test:e2e": "cross-env NODE_ENV=production playwright test",
"test-dev:e2e": "cross-env NODE_ENV=production playwright test --ui",
"preinstall": "corepack pnpm run generate-metadata && corepack pnpm run download-fonts",
"preinstall": "corepack pnpm run generate-metadata",
"postinstall": "playwright install",
"build-rust-ffi": "wasm-pack build ./rust-ffi --release --target web && wasm-pack build ./rust-ffi --out-dir node-pkg --target nodejs",
"generate-metadata": "node scripts/generateIconMetadata.js",
"download-fonts": "node scripts/downloadFonts.js"
"generate-metadata": "node scripts/generateIconMetadata.js"
},
"dependencies": {
"@aws-amplify/auth": "5.6.5",
@ -166,7 +165,6 @@
"@types/mapbox-gl": "^2.7.13",
"@types/shuffle-seed": "^1.1.0",
"@types/tar": "^6.1.4",
"@types/unbzip2-stream": "^1.4.3",
"@types/wicg-file-system-access": "^2023.10.2",
"@types/ws": "^8.5.5",
"@vitejs/plugin-vue": "^5.0.4",
@ -188,7 +186,6 @@
"sql-formatter": "^13.0.0",
"tar": "^6.2.1",
"tsx": "^4.7.1",
"unbzip2-stream": "^1.4.3",
"vite-plugin-vue-devtools": "7.3.7",
"vite-plugin-wasm": "^3.3.0",
"vue-react-wrapper": "^0.3.1",

View File

@ -1,217 +0,0 @@
/**
* @file THIS SCRIPT IS PROVIDED ONLY FOR CONVENIENCE.
* The sources of truth are at `build/build/src/project/gui.rs` and
* `build/build/src/ide/web/fonts.rs`.
*/
import * as fsSync from 'node:fs'
import * as fs from 'node:fs/promises'
import * as http from 'node:http'
import * as https from 'node:https'
import * as process from 'node:process'
import tar from 'tar'
import bz2 from 'unbzip2-stream'
if (process.env.CI === '1') process.exit(0)
const WARNING_MESSAGE =
'⚠️⚠️⚠️ Please use the buildscript (`./run`) to download fonts instead. ⚠️⚠️⚠️'
let warningMessageAlreadyShown = false
let exitCode = 0
const ENSO_FONT_URL = 'https://github.com/enso-org/font/releases/download/1.0/enso-font-1.0.tar.gz'
const MPLUS1_FONT_URL =
'https://github.com/coz-m/MPLUS_FONTS/raw/71d438c798d063cc6fdae8d2864bc48f2d3d06ad/fonts/ttf/MPLUS1%5Bwght%5D.ttf'
const DEJAVU_SANS_MONO_FONT_URL =
'https://sourceforge.net/projects/dejavu/files/dejavu/2.37/dejavu-fonts-ttf-2.37.tar.bz2'
/**
* @param {string | https.RequestOptions | URL} options
* @param {((res: import('node:http').IncomingMessage) => void) | undefined} [callback]
*/
function get(options, callback) {
const protocol =
typeof options === 'string' ? new URL(options).protocol : options.protocol ?? 'https:'
/** @type {{ get: typeof http['get'] }} */
let httpModule = https
switch (protocol) {
case 'http:': {
httpModule = http
break
}
}
return httpModule.get(options, (response) => {
const location = response.headers.location
if (location) {
get(
typeof options === 'string' || options instanceof URL ?
location
: { ...options, ...new URL(location) },
callback,
)
} else {
callback?.(response)
}
})
}
/** @param {unknown} error */
function errorCode(error) {
return (
typeof error === 'object' &&
error != null &&
'code' in error &&
typeof error.code === 'string'
) ?
error.code
: undefined
}
/** @param {unknown} error */
function isFileNotFoundError(error) {
return errorCode(error) === 'ENOENT'
}
const ENSO_FONT_VARIANTS = [
{ variant: 'Thin', weight: 100 },
{ variant: 'ExtraLight', weight: 200 },
{ variant: 'Light', weight: 300 },
{ variant: 'Regular', weight: 400 },
{ variant: 'Medium', weight: 500 },
{ variant: 'SemiBold', weight: 600 },
{ variant: 'Bold', weight: 700 },
{ variant: 'ExtraBold', weight: 800 },
{ variant: 'Black', weight: 900 },
].map((variant) => ({ font: 'Enso', ...variant }))
const DEJAVU_FONT_VARIANTS = [
{ variant: 'DejaVuSansMono', weight: 400 },
{ variant: 'DejaVuSansMono-Bold', weight: 700 },
].map((variant) => ({ font: 'DejaVu Sans Mono', ...variant }))
try {
await fs.access(`./src/project-view/assets/font-enso.css`)
for (const { variant } of ENSO_FONT_VARIANTS) {
await fs.access(`./public/font-enso/Enso-${variant}.ttf`)
}
console.info('Enso font already downloaded, skipping...')
} catch (error) {
if (!isFileNotFoundError(error)) {
console.error('Unexpected error occurred when checking for Enso font:')
console.error(error)
exitCode = 1
} else {
if (!warningMessageAlreadyShown) console.warn(WARNING_MESSAGE)
warningMessageAlreadyShown = true
console.info('Downloading Enso font...')
await fs.rm('./public/font-enso/', { recursive: true, force: true })
await fs.mkdir('./public/font-enso/', { recursive: true })
await new Promise((resolve, reject) => {
get(ENSO_FONT_URL, (response) => {
response.pipe(
tar.extract({
cwd: './public/font-enso/',
strip: 1,
filter(path) {
// Reject files starting with `.`.
return !/[\\/][.]/.test(path)
},
}),
)
response.on('end', resolve)
response.on('error', reject)
})
})
/** @type {string[]} */
let css = []
for (const { font, variant, weight } of ENSO_FONT_VARIANTS) {
css.push(`\
@font-face {
font-family: '${font}';
src: url('/font-enso/Enso-${variant}.ttf');
font-weight: ${weight};
}
`)
}
await fs.writeFile('./src/project-view/assets/font-enso.css', css.join('\n'))
}
}
try {
await fs.access(`./src/project-view/assets/font-mplus1.css`)
await fs.access(`./public/font-mplus1/MPLUS1[wght].ttf`)
console.info('M PLUS 1 font already downloaded, skipping...')
} catch (error) {
if (!isFileNotFoundError(error)) {
console.error('Unexpected error occurred when checking for M PLUS 1 font:')
console.error(error)
exitCode = 1
} else {
if (!warningMessageAlreadyShown) console.warn(WARNING_MESSAGE)
warningMessageAlreadyShown = true
console.info('Downloading M PLUS 1 font...')
await fs.rm('./public/font-mplus1/', { recursive: true, force: true })
await fs.mkdir('./public/font-mplus1/', { recursive: true })
await new Promise((resolve, reject) => {
get(MPLUS1_FONT_URL, (response) => {
response.pipe(fsSync.createWriteStream('./public/font-mplus1/MPLUS1[wght].ttf'))
response.on('end', resolve)
response.on('error', reject)
})
})
const css = `\
@font-face {
font-family: 'M PLUS 1';
src: url('/font-mplus1/MPLUS1[wght].ttf');
}
`
await fs.writeFile('./src/project-view/assets/font-mplus1.css', css)
}
}
try {
await fs.access(`./src/project-view/assets/font-dejavu.css`)
for (const variant of ['', '-Bold']) {
await fs.access(`./public/font-dejavu/DejaVuSansMono${variant}.ttf`)
}
console.info('DejaVu Sans Mono font already downloaded, skipping...')
} catch (error) {
if (!isFileNotFoundError(error)) {
console.error('Unexpected error occurred when checking for DejaVu Sans Mono font:')
console.error(error)
exitCode = 1
} else {
if (!warningMessageAlreadyShown) console.warn(WARNING_MESSAGE)
warningMessageAlreadyShown = true
console.info('Downloading DejaVu Sans Mono font...')
await fs.rm('./public/font-dejavu/', { recursive: true, force: true })
await fs.mkdir('./public/font-dejavu/', { recursive: true })
await new Promise((resolve, reject) => {
get(DEJAVU_SANS_MONO_FONT_URL, (response) => {
response.pipe(bz2()).pipe(
tar.extract({
cwd: './public/font-dejavu/',
strip: 2,
filter(path) {
return /[\\/]DejaVuSansMono/.test(path) && !/Oblique[.]ttf$/.test(path)
},
}),
)
response.on('end', resolve)
response.on('error', reject)
})
})
/** @type {string[]} */
let css = []
for (const { font, variant, weight } of DEJAVU_FONT_VARIANTS) {
css.push(`\
@font-face {
font-family: '${font}';
src: url('/font-dejavu/${variant}.ttf');
font-weight: ${weight};
}
`)
}
await fs.writeFile('./src/project-view/assets/font-dejavu.css', css.join('\n'))
}
}
console.info('Done.')
process.exit(exitCode)

View File

@ -0,0 +1,12 @@
@font-face {
font-family: 'DejaVu Sans Mono';
src: url('/font-dejavu/DejaVuSansMono.ttf');
font-weight: 400;
}
@font-face {
font-family: 'DejaVu Sans Mono';
src: url('/font-dejavu/DejaVuSansMono-Bold.ttf');
font-weight: 700;
}

View File

@ -0,0 +1,54 @@
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-Thin.ttf');
font-weight: 100;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-ExtraLight.ttf');
font-weight: 200;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-Light.ttf');
font-weight: 300;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-Regular.ttf');
font-weight: 400;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-Medium.ttf');
font-weight: 500;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-SemiBold.ttf');
font-weight: 600;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-Bold.ttf');
font-weight: 700;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-ExtraBold.ttf');
font-weight: 800;
}
@font-face {
font-family: 'Enso';
src: url('/font-enso/Enso-Black.ttf');
font-weight: 900;
}

View File

@ -0,0 +1,5 @@
@font-face {
font-family: 'M PLUS 1';
src: url('/font-mplus1/MPLUS1[wght].ttf');
}

View File

@ -1,213 +0,0 @@
[
"3_dot_menu",
"accessed_by_projects",
"accessed_data",
"add",
"add_to_graph_editor",
"array_new",
"array_new2",
"arrow_left",
"arrow_right",
"arrow_right_head_only",
"auto_replay",
"bell",
"bold",
"bookmark",
"bottom_panel",
"braces",
"brush",
"bullet-list",
"calendar",
"camera",
"chat",
"chat_gpt",
"chat_gpt2",
"chat_gpt_mod",
"chat_gpt_mod2",
"check",
"check-list",
"clone",
"close",
"cloud",
"cloud_from",
"code",
"collection",
"column_add",
"columns_increasing",
"command",
"command2",
"command3",
"command4",
"command5",
"comment",
"compass",
"compliance",
"compliance2",
"connector",
"connector_add",
"convert",
"copy",
"copy2",
"credit_card",
"data_download",
"data_input",
"data_output",
"data_upload",
"datetime",
"docs",
"drive",
"duplicate",
"edit",
"enso_logo",
"enter_node",
"error",
"exclamation",
"exit_fullscreen",
"expanded_node",
"eye",
"find",
"folder",
"folder_add",
"folder_closed",
"folder_opened",
"fullscreen",
"fullscreen2",
"fullscreen3",
"geo_map_distance",
"geo_map_pin",
"ghost",
"google",
"google_color",
"graph",
"graph2",
"graph_editor",
"graph_editor",
"group",
"header1",
"header2",
"header3",
"heart",
"heatmap",
"help",
"home",
"home2",
"icon/lock",
"icon/skip",
"image",
"in_out",
"in_out2",
"input_number",
"italic",
"join",
"join-1",
"join2",
"join2-1",
"key",
"key_cmd",
"key_ctrl",
"key_option",
"keyboard_shortcuts",
"lab",
"lab2",
"lab3",
"libraries",
"local_scope",
"local_scope2",
"local_scope3",
"local_scope4",
"location",
"location2",
"log",
"log_cloud",
"make_node_def_local_copy",
"map_row",
"marketplace",
"math",
"metadata",
"microphone",
"minus",
"mixed",
"no_auto_replay",
"not_cloud",
"not_exclamation",
"not_paragraph",
"numbered-list",
"open",
"open_count",
"operators",
"order",
"paint",
"paint_palette",
"panic",
"paragraph",
"parse",
"parse2",
"parse3",
"parse4",
"path2",
"people",
"people_settings",
"points",
"predict",
"preparation",
"quote",
"random",
"recent",
"record",
"record_once",
"redo",
"refresh",
"remove-textstyle",
"restore",
"right_panel",
"right_side_panel",
"robot",
"root",
"row_add",
"scissors",
"select",
"select_column",
"select_row",
"settings",
"settings1",
"settings2",
"shift_key",
"shortcut",
"shortcut2",
"shortcut3",
"show_all",
"sort",
"sort_ascending",
"sort_descending",
"split",
"star",
"strike-through",
"system",
"table",
"table_clean",
"table_edit",
"table_from_columns",
"table_from_rows",
"tag",
"temp",
"text",
"text2",
"text3",
"text_input",
"time",
"time2",
"transform",
"transform2",
"transform3",
"transform4",
"trash",
"trash2",
"undo",
"union",
"unstable",
"unstable2",
"vector_add",
"warning",
"workflow_play",
"zoom"
]

View File

@ -21,8 +21,6 @@ futures = { workspace = true }
glob = "0.3.0"
handlebars = "4.3.5"
enso-build-base = { path = "../base" }
enso-enso-font = { path = "../../lib/rust/enso-font" }
enso-font = { path = "../../lib/rust/font" }
enso-install-config = { path = "../install/config" }
ide-ci = { path = "../ci_utils" }
mime = { workspace = true }

View File

@ -21,13 +21,6 @@ use tempfile::TempDir;
// === Export ===
// ==============
pub mod dejavu_font;
pub mod enso_font;
pub mod fonts;
pub mod google_font;
lazy_static! {
/// Path to the file with build information that is consumed by the JS part of the IDE.
///

View File

@ -1,134 +0,0 @@
//! Definitions for DejaVu fonts, and functions for downloading and installing them.
use crate::prelude::*;
use enso_font as font;
use enso_font::NonVariableDefinition;
use enso_font::NonVariableFaceHeader;
use ide_ci::cache::Cache;
// =================
// === Constants ===
// =================
pub const PACKAGE_URL: &str = "https://github.com/dejavu-fonts/dejavu-fonts/releases/download/version_2_37/dejavu-fonts-ttf-2.37.zip";
const FONT_FAMILY: &str = "DejaVu Sans Mono";
const FILE_PREFIX: &str = "DejaVu";
const FILE_SANS_MONO_PREFIX: &str = "SansMono";
const SANS_MONO_FONT_FAMILY_FONTS: &[(&str, font::Weight)] =
&[("-Bold", font::Weight::Bold), ("", font::Weight::Normal)];
// ===================
// === DejaVu Font ===
// ===================
/// Internal helper function to download the DejaVu Sans Mono font. Exposed via thin wrapper
/// functions.
async fn install_sans_mono_internal(
cache: &Cache,
octocrab: &Octocrab,
output_path: impl AsRef<Path>,
css_output_info: Option<(&str, impl AsRef<Path>)>,
) -> Result {
let output_path = output_path.as_ref();
let font = font();
let faces = faces();
let font = crate::ide::web::fonts::filter_font(&font, &faces);
let package = download(cache, octocrab).await?;
let get_font_files = extract_fonts(&font, package, output_path);
let make_css_file = crate::ide::web::fonts::write_css_file_if_required(
FONT_FAMILY,
&font,
&faces,
css_output_info,
);
try_join!(get_font_files, make_css_file)?;
Ok(())
}
/// Install DejaVu Sans Mono, without an auto-generated CSS file.
pub async fn install_sans_mono(
cache: &Cache,
octocrab: &Octocrab,
output_path: impl AsRef<Path>,
) -> Result {
install_sans_mono_internal(cache, octocrab, output_path, None::<(&str, &str)>).await
}
/// Install DejaVu Sans Mono, including an auto-generated CSS file.
pub async fn install_sans_mono_with_css(
cache: &Cache,
octocrab: &Octocrab,
css_basepath: &str,
output_path: impl AsRef<Path>,
css_output_path: impl AsRef<Path>,
) -> Result {
install_sans_mono_internal(cache, octocrab, output_path, Some((css_basepath, css_output_path)))
.await
}
/// The DejaVu Sans Mono Font.
pub fn font() -> NonVariableDefinition {
SANS_MONO_FONT_FAMILY_FONTS
.iter()
.map(|(name, weight)| {
let file = format!("{FILE_PREFIX}{FILE_SANS_MONO_PREFIX}{name}.ttf");
let header = NonVariableFaceHeader {
weight: *weight,
width: font::Width::Normal,
style: font::Style::Normal,
};
(header, file)
})
.collect()
}
/// All font faces contained in this font.
pub fn faces() -> [NonVariableFaceHeader; 2] {
[NonVariableFaceHeader { weight: font::Weight::Normal, ..default() }, NonVariableFaceHeader {
weight: font::Weight::Bold,
..default()
}]
}
/// Extract the fonts from the given archive file, and write them in the given directory.
pub async fn extract_fonts(
fonts: &NonVariableDefinition,
package: impl AsRef<Path>,
out_dir: impl AsRef<Path>,
) -> Result {
let mut archive = ide_ci::archive::zip::open(&package)?;
crate::ide::web::fonts::extract_fonts(&mut archive, fonts, package, out_dir, &mut |path| {
let mut iter = path.iter();
for _ in iter.by_ref().take(2) {}
Box::from(iter.as_str())
})
.await
}
/// Download the DejaVu Font package, with caching and GitHub authentication.
pub async fn download(cache: &Cache, octocrab: &Octocrab) -> Result<Box<Path>> {
Ok(cache
.get(ide_ci::cache::download::DownloadFile {
client: octocrab.client.clone(),
key: ide_ci::cache::download::Key {
url: PACKAGE_URL.parse().unwrap(),
additional_headers: reqwest::header::HeaderMap::from_iter([(
reqwest::header::ACCEPT,
reqwest::header::HeaderValue::from_static(
mime::APPLICATION_OCTET_STREAM.as_ref(),
),
)]),
},
})
.await?
.into_boxed_path())
}

View File

@ -1,114 +0,0 @@
//! Definitions for Enso Font, and functions for downloading and installing them.
use crate::prelude::*;
use enso_enso_font::ttf;
use enso_font::NonVariableFaceHeader;
use ide_ci::cache::Cache;
// =================
// === Constants ===
// =================
const FONT_FAMILY: &str = "Enso";
// =================
// === Enso Font ===
// =================
pub async fn install_for_html(
cache: &Cache,
octocrab: &Octocrab,
output_path: impl AsRef<Path>,
) -> Result {
let output_path = output_path.as_ref();
let html_fonts: HashMap<_, _> = [
(NonVariableFaceHeader { weight: ttf::Weight::Normal, ..default() }, "Regular"),
(NonVariableFaceHeader { weight: ttf::Weight::ExtraBold, ..default() }, "Bold"),
]
.into_iter()
.collect();
let html_font_definitions = enso_enso_font::font()
.variations()
.filter(|v| html_fonts.contains_key(&v.header))
.collect();
let get_font_files = async {
let package = download(cache, octocrab).await?;
enso_enso_font::extract_fonts(&html_font_definitions, package, output_path).await
};
let make_css_file = async {
let mut css = String::new();
let url = ".";
for (header, variant) in html_fonts {
use std::fmt::Write;
let def = html_font_definitions.get(header);
let def = def.ok_or_else(|| {
anyhow!(
"Required font not found in Enso Font package. \
Expected a font matching: {header:?}."
)
})?;
let file = &def.file;
// Note that this cannot use `generate_css_file`, as it specifies a different font
// family for each variant.
writeln!(&mut css, "@font-face {{")?;
writeln!(&mut css, " font-family: '{FONT_FAMILY}{variant}';")?;
writeln!(&mut css, " src: url('{url}/{file}');")?;
writeln!(&mut css, " font-weight: normal;")?;
writeln!(&mut css, " font-style: normal;")?;
writeln!(&mut css, "}}")?;
}
let css_path = output_path.join("ensoFont.css");
ide_ci::fs::tokio::write(css_path, css).await?;
Ok(())
};
try_join!(get_font_files, make_css_file)?;
Ok(())
}
pub async fn install_with_css(
cache: &Cache,
octocrab: &Octocrab,
css_basepath: &str,
output_path: impl AsRef<Path>,
css_output_path: impl AsRef<Path>,
) -> Result {
let output_path = output_path.as_ref();
let font = enso_enso_font::font();
let faces = enso_enso_font::faces();
let font = crate::ide::web::fonts::filter_font(&font, &faces);
let package = download(cache, octocrab).await?;
let get_font_files = enso_enso_font::extract_fonts(&font, package, output_path);
let css_output_info = Some((css_basepath, css_output_path));
let make_css_file = crate::ide::web::fonts::write_css_file_if_required(
FONT_FAMILY,
&font,
&faces,
css_output_info,
);
try_join!(get_font_files, make_css_file)?;
Ok(())
}
/// Download the Enso Font package, with caching and GitHub authentication.
pub async fn download(cache: &Cache, octocrab: &Octocrab) -> Result<Box<Path>> {
Ok(cache
.get(ide_ci::cache::download::DownloadFile {
client: octocrab.client.clone(),
key: ide_ci::cache::download::Key {
url: enso_enso_font::PACKAGE_URL.parse().unwrap(),
additional_headers: reqwest::header::HeaderMap::from_iter([(
reqwest::header::ACCEPT,
reqwest::header::HeaderValue::from_static(
mime::APPLICATION_OCTET_STREAM.as_ref(),
),
)]),
},
})
.await?
.into_boxed_path())
}

View File

@ -1,192 +0,0 @@
use crate::prelude::*;
use enso_font::NonVariableDefinition;
use enso_font::NonVariableFaceHeader;
use ide_ci::archive::extract_files::ExtractFiles;
use ide_ci::cache::Cache;
// =========================
// === HTML Font Support ===
// =========================
pub async fn install_html_fonts(
cache: &Cache,
octocrab: &Octocrab,
output_path: impl AsRef<Path>,
) -> Result {
let output_path = output_path.as_ref();
crate::ide::web::google_font::install(cache, octocrab, "mplus1", output_path).await?;
crate::ide::web::enso_font::install_for_html(cache, octocrab, output_path).await?;
Ok(())
}
/// A CSS font style that is displayed as a CSS [`@font-face`] [`font-style`] value.
///
/// [`@font-face`]: https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face
/// [`font-style`]: https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-style
#[derive(Debug, Display, Copy, Clone)]
pub enum FontStyle {
#[display("normal")]
Normal,
#[display("italic")]
Italic,
#[display("oblique")]
Oblique,
/// Angle is in degrees, between -90 and 90.
#[display("oblique {_0}deg")]
ObliqueWithAngle(f64),
/// Angles are in degrees, between -90 and 90.
#[display("oblique {_0}deg {_1}deg")]
ObliqueWithAngleRange(f64, f64),
}
/// A CSS font face that is displayed as a CSS [`@font-face`] declaration.
///
/// [`@font-face`]: https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face
#[derive(Debug, Clone)]
pub struct FontFace<'a> {
family: Cow<'a, str>,
path: Cow<'a, str>,
weight: Option<u16>,
style: Option<FontStyle>,
}
impl Display for FontFace<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let family = &self.family;
let path = &self.path;
writeln!(f, "@font-face {{")?;
writeln!(f, " font-family: '{family}';")?;
writeln!(f, " src: url('{path}');")?;
if let Some(weight) = self.weight {
writeln!(f, " font-weight: {weight};")?;
}
if let Some(style) = self.style {
writeln!(f, " font-style: {style};")?;
}
writeln!(f, "}}")?;
Ok(())
}
}
/// Generate a CSS file containing the given font files. Does not include font-weight, so use this
/// only if the font weights are not known - prefer [`generate_css_file`] in all other cases.
pub fn generate_css_file_from_paths<AsRefStr>(
basepath: &str,
family: &str,
paths: impl Iterator<Item = AsRefStr>,
) -> Result<String>
where
AsRefStr: AsRef<str>,
{
let mut css = String::new();
for path in paths {
use std::fmt::Write;
let path = format!("{basepath}/{}", path.as_ref());
let font_face = FontFace {
family: Cow::Borrowed(family),
path: Cow::Borrowed(path.as_str()),
weight: None,
style: None,
};
writeln!(&mut css, "{font_face}")?;
}
Ok(css)
}
/// Generate a CSS file containing the given font family, including only the given font variations.
pub fn generate_css_file<'a>(
basepath: &str,
family: &str,
definitions: &NonVariableDefinition,
fonts: impl Iterator<Item = &'a NonVariableFaceHeader>,
) -> Result<String> {
let mut css = String::new();
for header in fonts {
use std::fmt::Write;
let def = definitions.get(*header);
let def = def.ok_or_else(|| {
anyhow!(
"Required font not found in {family} Font package. \
Expected a font matching: {header:?}."
)
})?;
let path = format!("{basepath}/{}", def.file);
let weight = def.header.weight.to_number();
let font_face = FontFace {
family: Cow::Borrowed(family),
path: Cow::Borrowed(path.as_str()),
weight: Some(weight),
style: None,
};
writeln!(&mut css, "{font_face}")?;
}
Ok(css)
}
// ===================
// === Filter Font ===
// ===================
pub fn filter_font(
font: &NonVariableDefinition,
faces: &[NonVariableFaceHeader],
) -> NonVariableDefinition {
font.variations().filter(|v| faces.contains(&v.header)).collect()
}
// =====================
// === Make CSS File ===
// =====================
pub async fn write_css_file_if_required(
font_family: &str,
font: &NonVariableDefinition,
faces: &[NonVariableFaceHeader],
css_output_info: Option<(&str, impl AsRef<Path>)>,
) -> Result {
if let Some((css_basepath, css_output_path)) = css_output_info {
let contents = generate_css_file(css_basepath, font_family, font, faces.iter())?;
ide_ci::fs::tokio::write(css_output_path, contents).await?;
Ok(())
} else {
Ok(())
}
}
// =====================
// === Extract Fonts ===
// =====================
/// Extract the fonts from the given archive file, and write them in the given directory.
#[context("Failed to extract fonts from archive {}", package.as_ref().display())]
pub async fn extract_fonts(
archive: impl ExtractFiles,
fonts: &NonVariableDefinition,
package: impl AsRef<Path>,
out_dir: impl AsRef<Path>,
normalize_path: &mut impl FnMut(&Path) -> Box<str>,
) -> Result {
ide_ci::fs::tokio::create_dir_if_missing(out_dir.as_ref()).await?;
let mut files_expected: HashSet<_> = fonts.files().collect();
archive
.extract_files(|path_in_archive| {
let stripped_path = normalize_path(path_in_archive);
if files_expected.remove(stripped_path.as_ref()) {
Some(out_dir.as_ref().join(stripped_path.as_ref()))
} else {
None
}
})
.await?;
ensure!(files_expected.is_empty(), "Required fonts not found in archive: {files_expected:?}.");
Ok(())
}

View File

@ -1,196 +0,0 @@
//! Functions for downloading and installing Google fonts.
use crate::prelude::*;
use ide_ci::cache::Cache;
use ide_ci::cache::Storable;
use ide_ci::github;
use ide_ci::github::RepoRef;
use octocrab::models::repos;
// =================
// === Constants ===
// =================
/// Google Fonts repository.
pub const REPOSITORY: RepoRef = RepoRef { owner: "google", name: "fonts" };
/// Path to the directory on the Google Fonts repository where we get the fonts from.
///
/// The directory name denotes the license of the fonts. In our case this is SIL OPEN FONT LICENSE
/// Version 1.1, commonly known as OFL.
pub const DIRECTORY: &str = "ofl";
/// We keep dependency to a fixed commit, so we can safely cache it.
///
/// There are no known reasons not to bump this.
pub const COMMIT_SHA1: &str = "ea893a43af7c5ab5ccee189fc2720788d99887ed";
// ==============
// === Family ===
// ==============
/// Identifies uniquely a source of font family download.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Family {
/// Remote repository with fonts.
pub repo: github::Repo,
/// Which commit we want to be downloaded.
pub r#ref: String,
/// Font family. It corresponds to the subdirectories names (under the top-level
/// license-denoting directories).
pub name: String,
}
impl Family {
/// List content items in the repository that contain TTF files for the given font family.
pub async fn list_ttf(
&self,
handle: github::repo::Handle<impl IsRepo>,
) -> Result<Vec<repos::Content>> {
let path = format!("{DIRECTORY}/{}", self.name);
let files = handle.repos().get_content().r#ref(&self.r#ref).path(path).send().await?;
Ok(files.items.into_iter().filter(|file| file.name.ends_with(".ttf")).collect())
}
}
// ====================
// === DownloadFont ===
// ====================
/// Description of the job to download the fonts.
#[derive(Clone)]
#[derive_where(Debug)]
pub struct DownloadFont {
pub family: Family,
/// Possible authentication to GitHub (to get bigger rate limit).
#[derive_where(skip)]
pub octocrab: Octocrab,
}
impl DownloadFont {
/// Get a handle to the remote repository with the fonts.
pub fn handle(&self) -> github::repo::Handle<impl IsRepo> {
self.family.repo.handle(&self.octocrab)
}
/// Download the font family to the given directory. They will be placed in the output
/// directory. The function returns relative paths to the downloaded files.
pub async fn download(&self, output_path: impl AsRef<Path>) -> Result<Vec<PathBuf>> {
let files = self.family.list_ttf(self.handle()).await?;
let mut ret = Vec::new();
for file in &files {
let destination_file = output_path.as_ref().join(&file.name);
let url = file.download_url.as_ref().context("Missing 'download_url' in the reply.")?;
let reply = ide_ci::io::web::client::download(&self.octocrab.client, url).await?;
ide_ci::io::web::stream_to_file(reply, &destination_file).await?;
ret.push(file.name.as_str().into());
}
Ok(ret)
}
}
impl Storable for DownloadFont {
/// In metadata form we just store paths relative to the store.
type Metadata = Vec<PathBuf>;
/// Here paths are absolute.
type Output = Vec<PathBuf>;
type Key = Family;
fn generate(
&self,
_cache: Cache,
store: PathBuf,
) -> BoxFuture<'static, Result<Self::Metadata>> {
let this = self.clone();
async move {
let fonts = this.download(&store).await?;
Ok(fonts)
}
.boxed()
}
fn adapt(
&self,
cache: PathBuf,
mut metadata: Self::Metadata,
) -> BoxFuture<'static, Result<Self::Output>> {
async move {
for font in &mut metadata {
*font = cache.join(&*font);
}
Ok(metadata)
}
.boxed()
}
fn key(&self) -> Self::Key {
self.family.clone()
}
}
// ===================
// === Entry Point ===
// ===================
/// Install a Google font, without an auto-generated CSS file.
pub async fn install(
cache: &Cache,
octocrab: &Octocrab,
family: &str,
output_path: impl AsRef<Path>,
) -> Result<Vec<PathBuf>> {
let family =
Family { repo: REPOSITORY.into(), r#ref: COMMIT_SHA1.into(), name: family.into() };
let font = DownloadFont { family, octocrab: octocrab.clone() };
let cached_fonts = cache.get(font).await?;
let copy_futures =
cached_fonts.into_iter().map(|font| ide_ci::fs::tokio::copy_to(font, &output_path));
let result = futures::future::join_all(copy_futures).await.into_iter().try_collect()?;
Ok(result)
}
/// Install a Google font, including an auto-generated CSS file.
pub async fn install_with_css(
cache: &Cache,
octocrab: &Octocrab,
family: &str,
css_family: &str,
css_basepath: &str,
output_path: impl AsRef<Path>,
css_output_path: impl AsRef<Path>,
) -> Result<Vec<PathBuf>> {
let paths = install(cache, octocrab, family, output_path).await?;
let css = crate::ide::web::fonts::generate_css_file_from_paths(
css_basepath,
css_family,
paths.iter().flat_map(|path| path.try_file_name().map(|name| name.as_str())),
)?;
ide_ci::fs::tokio::write(css_output_path, css).await?;
Ok(paths)
}
// =============
// === Tests ===
// =============
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
#[ignore]
async fn new_download() -> Result {
setup_logging().ok();
let path = r"C:\temp\google_fonts2";
let octocrab = github::setup_octocrab().await?;
let cache = Cache::new_default().await?;
let aaa = install(&cache, &octocrab, "mplus1", path).await?;
dbg!(aaa);
Ok(())
}
}

View File

@ -64,32 +64,6 @@ impl IsTarget for Gui {
let WithDestination { inner: _, destination } = job;
async move {
let repo_root = &context.repo_root;
crate::ide::web::google_font::install_with_css(
&context.cache,
&context.octocrab,
"mplus1",
"M PLUS 1",
"/font-mplus1",
&repo_root.app.gui.public.font_mplus_1,
&repo_root.app.gui.src.project_view.assets.font_mplus_1_css,
)
.await?;
crate::ide::web::dejavu_font::install_sans_mono_with_css(
&context.cache,
&context.octocrab,
"/font-dejavu",
&repo_root.app.gui.public.font_dejavu,
&repo_root.app.gui.src.project_view.assets.font_dejavu_css,
)
.await?;
crate::ide::web::enso_font::install_with_css(
&context.cache,
&context.octocrab,
"/font-enso",
&repo_root.app.gui.public.font_enso,
&repo_root.app.gui.src.project_view.assets.font_enso_css,
)
.await?;
crate::web::install(repo_root).await?;
crate::web::run_script(repo_root, crate::web::Script::Build).await?;
ide_ci::fs::mirror_directory(

View File

@ -191,6 +191,7 @@ export default [
'**/.cache/**',
'**/playwright-report',
'**/dist',
'**/mockDist',
'**/build.mjs',
'**/*.timestamp-*.mjs',
'**/node_modules',

View File

@ -1,13 +0,0 @@
[package]
name = "enso-enso-font"
version = "0.1.0"
authors = ["Enso Team <contact@enso.org>"]
edition = "2021"
[dependencies]
enso-font = { path = "../font" }
ide-ci = { path = "../../../build/ci_utils" }
owned_ttf_parser = { workspace = true }
[lints]
workspace = true

View File

@ -1,112 +0,0 @@
//! The Enso Font. This crate supports downloading and unpacking the font family, as well as
//! constructing a reduced font family from a subset of the fonts.
// === Non-Standard Linter Configuration ===
#![deny(unconditional_recursion)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
use ide_ci::prelude::*;
use enso_font::NonVariableDefinition;
use enso_font::NonVariableFaceHeader;
// ==============
// === Export ===
// ==============
pub use owned_ttf_parser as ttf;
// =================
// === Constants ===
// =================
/// The name of the Enso font family.
pub const FONT_FAMILY: &str = "enso";
const FONTS: &[(&str, ttf::Weight)] = &[
("Black", ttf::Weight::Black),
("Bold", ttf::Weight::Bold),
("ExtraBold", ttf::Weight::ExtraBold),
("ExtraLight", ttf::Weight::ExtraLight),
("Light", ttf::Weight::Light),
("Medium", ttf::Weight::Medium),
("Regular", ttf::Weight::Normal),
("SemiBold", ttf::Weight::SemiBold),
("Thin", ttf::Weight::Thin),
];
/// The URL for the Enso Font package.
pub const PACKAGE_URL: &str =
"https://github.com/enso-org/font/releases/download/1.0/enso-font-1.0.tar.gz";
const PACKAGE_FONTS_PREFIX: &str = "ttf";
/// Font features.
pub mod feature {
/// The flag identifying the ligature feature in this font.
pub const LIGATURES: &str = "liga";
}
// =================
// === Enso Font ===
// =================
/// The Enso Font.
pub fn font() -> NonVariableDefinition {
FONTS
.iter()
.map(|(name, weight)| {
let file = format!("Enso-{name}.ttf");
let header = NonVariableFaceHeader {
weight: *weight,
width: ttf::Width::Normal,
style: ttf::Style::Normal,
};
(header, file)
})
.collect()
}
/// All font faces contained in this font.
pub fn faces() -> [NonVariableFaceHeader; 9] {
[
NonVariableFaceHeader { weight: ttf::Weight::Thin, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::ExtraLight, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::Light, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::Normal, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::Medium, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::SemiBold, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::Bold, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::ExtraBold, ..default() },
NonVariableFaceHeader { weight: ttf::Weight::Black, ..default() },
]
}
/// Extract the fonts from the given archive file, and write them in the given directory.
#[context("Failed to extract fonts from archive {}", package.as_ref().display())]
pub async fn extract_fonts(
fonts: &NonVariableDefinition,
package: impl AsRef<Path>,
out_dir: impl AsRef<Path>,
) -> Result {
use ide_ci::archive::extract_files::ExtractFiles;
ide_ci::fs::tokio::create_dir_if_missing(out_dir.as_ref()).await?;
let mut files_expected: HashSet<_> = fonts.files().collect();
ide_ci::archive::tar::Archive::open_tar_gz(&package)
.await?
.extract_files(|path_in_archive| {
path_in_archive
.strip_prefix(PACKAGE_FONTS_PREFIX)
.ok()
.filter(|path| path.to_str().map_or(false, |path| files_expected.remove(path)))
.map(|path| out_dir.as_ref().join(path))
})
.await?;
ensure!(files_expected.is_empty(), "Required fonts not found in archive: {files_expected:?}.");
Ok(())
}

View File

@ -1,15 +0,0 @@
[package]
name = "enso-font"
version = "0.1.0"
authors = ["Enso Team <contact@enso.org>"]
edition = "2021"
[dependencies]
owned_ttf_parser = { workspace = true }
derive_more = { workspace = true }
[lib]
crate-type = ["cdylib", "rlib"]
[lints]
workspace = true

View File

@ -1,203 +0,0 @@
//! Definition of a font family, a set of related font faces.
//!
//! # One font face per file
//! The implementation of this library has an important limitation that should not cause any
//! problems, however, it is important to be aware of it. In case of non-variable fonts, only one
//! font face is supported per file. A font face is identified by (width, weight, style) triple (see
//! [`NonVariableFaceHeader`]) to learn more. If you want to use font faces defined in the same
//! file (e.g. ".ttf" file), you have to split them into multiple files first. All major browsers
//! have the same limitation. For example, you are unable to define in CSS a new font family by
//! loading different faces from the same file with the `@font-face` rule
//! (https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face).
// === Non-Standard Linter Configuration ===
#![deny(unconditional_recursion)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(unused_qualifications)]
use derive_more::Deref;
use derive_more::Display;
// ==============
// === Export ===
// ==============
pub use owned_ttf_parser::Style;
pub use owned_ttf_parser::Weight;
pub use owned_ttf_parser::Width;
// ============
// === Name ===
// ============
/// A name of a font. The name is normalized to case-insensitive form during construction to
/// eliminate accidental mistakes, the same way as it's done in CSS:
/// https://stackoverflow.com/questions/17967371/are-property-values-in-css-case-sensitive
#[allow(missing_docs)]
#[derive(Clone, Debug, Deref, Display, Hash, PartialEq, Eq)]
pub struct Name {
pub normalized: String,
}
impl From<&Name> for Name {
fn from(name: &Name) -> Self {
name.clone()
}
}
impl From<&str> for Name {
fn from(name: &str) -> Self {
let normalized = name.to_lowercase();
Name { normalized }
}
}
impl From<&String> for Name {
fn from(name: &String) -> Self {
name.as_str().into()
}
}
impl From<String> for Name {
fn from(name: String) -> Self {
(&name).into()
}
}
// ===================
// === Font Family ===
// ===================
/// Definition of a font family. Font family consist of one font face in case of variable fonts or
/// multiple font faces in case of non-variable ones.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FontFamily {
Variable(VariableDefinition),
NonVariable(NonVariableDefinition),
}
// ==========================
// === VariableDefinition ===
// ==========================
/// Definition of a variable font family. See the following link to learn more about variable fonts:
/// https://docs.microsoft.com/en-us/windows/win32/directwrite/opentype-variable-fonts
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VariableDefinition {
/// Name of the file that the font data was read from. It contains the file extension, for
/// example `MPLUS1[wght].ttf`.
pub file_name: String,
}
impl VariableDefinition {
/// Constructor.
pub fn new(file_name: impl Into<String>) -> Self {
let file_name = file_name.into();
Self { file_name }
}
}
// =============================
// === NonVariableDefinition ===
// =============================
/// Definition of a non-variable font family. Contains mapping between (width, weight, style) triple
/// (see [`NonVariableFaceHeader`]) to learn more) and file names.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NonVariableDefinition {
variations: std::collections::HashMap<NonVariableFaceHeader, String>,
}
impl NonVariableDefinition {
/// All weights defined in this font family.
pub fn possible_weights(&self) -> Vec<Weight> {
let mut weights: Vec<_> = self.variations().map(|var| var.header.weight).collect();
weights.sort_unstable_by_key(|w| w.to_number());
weights.dedup();
weights
}
/// Return an iterator over the filenames associated with fonts in this family.
pub fn files(&self) -> impl Iterator<Item = &str> {
self.variations().map(|v| v.file)
}
/// Return an iterator over the fonts in this family.
pub fn variations(&self) -> impl Iterator<Item = NonVariableVariation> {
self.variations
.iter()
.map(|(header, file)| NonVariableVariation { header: *header, file: file.as_str() })
}
/// Return the font in this family that exactly matches the given parameters, if any.
pub fn get(&self, header: NonVariableFaceHeader) -> Option<NonVariableVariation> {
self.variations.get(&header).map(|file| NonVariableVariation { header, file })
}
}
impl FromIterator<(NonVariableFaceHeader, String)> for NonVariableDefinition {
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = (NonVariableFaceHeader, String)> {
let map = iter.into_iter().collect();
Self { variations: map }
}
}
impl<'a> FromIterator<NonVariableVariation<'a>> for NonVariableDefinition {
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = NonVariableVariation<'a>> {
let map = iter.into_iter().map(|v| (v.header, v.file.to_owned())).collect();
Self { variations: map }
}
}
// ============================
// === NonVariableVariation ===
// ============================
/// The parameters of a font, and the filename where it should be found.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NonVariableVariation<'a> {
/// The parameters of the font.
pub header: NonVariableFaceHeader,
/// The filename for the font.
pub file: &'a str,
}
// =============================
// === NonVariableFaceHeader ===
// =============================
/// Combination of all information allowing mapping the font face to a font file for non-variable
/// fonts. For variable fonts, there is just one definition for any combination of the parameters.
#[allow(missing_docs)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
pub struct NonVariableFaceHeader {
pub width: Width,
pub weight: Weight,
pub style: Style,
}
impl NonVariableFaceHeader {
/// Constructor.
pub const fn new(width: Width, weight: Weight, style: Style) -> Self {
Self { width, weight, style }
}
}

View File

@ -428,9 +428,6 @@ importers:
'@types/tar':
specifier: ^6.1.4
version: 6.1.13
'@types/unbzip2-stream':
specifier: ^1.4.3
version: 1.4.3
'@types/validator':
specifier: ^13.11.7
version: 13.12.0
@ -524,9 +521,6 @@ importers:
typescript:
specifier: ^5.5.3
version: 5.5.3
unbzip2-stream:
specifier: ^1.4.3
version: 1.4.3
vite:
specifier: ^5.3.5
version: 5.3.5(@types/node@20.11.21)(lightningcss@1.25.1)
@ -3065,18 +3059,12 @@ packages:
'@types/tar@6.1.13':
resolution: {integrity: sha512-IznnlmU5f4WcGTh2ltRu/Ijpmk8wiWXfF0VA4s+HPjHZgvFggk1YaIkbo5krX/zUCzWF8N/l4+W/LNxnvAJ8nw==}
'@types/through@0.0.33':
resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==}
'@types/to-ico@1.1.3':
resolution: {integrity: sha512-3Ew8Hsz/qiDGzwvz75pjRU+6Ocfvrit6hHfirauEdJXxdro73MTe5XdcANh4GZ2wdJqWw9BIuHwWgKAfjUXoGw==}
'@types/tough-cookie@4.0.5':
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
'@types/unbzip2-stream@1.4.3':
resolution: {integrity: sha512-D8X5uuJRISqc8YtwL8jNW2FpPdUOCYXbfD6zNROCTbVXK9nawucxh10tVXE3MPjnHdRA1LvB0zDxVya/lBsnYw==}
'@types/validator@13.12.0':
resolution: {integrity: sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==}
@ -6960,9 +6948,6 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@ -7121,9 +7106,6 @@ packages:
unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
unbzip2-stream@1.4.3:
resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==}
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
@ -10504,20 +10486,12 @@ snapshots:
'@types/node': 20.11.21
minipass: 4.2.8
'@types/through@0.0.33':
dependencies:
'@types/node': 20.11.21
'@types/to-ico@1.1.3':
dependencies:
'@types/node': 20.11.21
'@types/tough-cookie@4.0.5': {}
'@types/unbzip2-stream@1.4.3':
dependencies:
'@types/through': 0.0.33
'@types/validator@13.12.0': {}
'@types/verror@1.10.10':
@ -15079,8 +15053,6 @@ snapshots:
dependencies:
any-promise: 1.3.0
through@2.3.8: {}
tiny-invariant@1.3.3: {}
tinybench@2.8.0: {}
@ -15238,11 +15210,6 @@ snapshots:
has-symbols: 1.0.3
which-boxed-primitive: 1.0.2
unbzip2-stream@1.4.3:
dependencies:
buffer: 5.7.1
through: 2.3.8
undici-types@5.26.5: {}
undici@6.13.0: {}