From 0fccae104988436b0fc140e8e6d3be8279da4e7e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 20 Aug 2024 21:40:32 -0600 Subject: [PATCH] Add experimental wasm bindings Published to npm as objdiff-wasm --- Cargo.lock | 35 +- objdiff-cli/Cargo.toml | 8 +- objdiff-cli/build.rs | 53 - objdiff-cli/protos/proto_descriptor.bin | Bin 7325 -> 0 bytes objdiff-cli/src/cmd/diff.rs | 251 +- objdiff-cli/src/cmd/report.rs | 94 +- objdiff-cli/src/main.rs | 2 +- objdiff-cli/src/util/mod.rs | 2 +- objdiff-cli/src/util/output.rs | 84 + objdiff-core/Cargo.toml | 13 +- objdiff-core/build.rs | 54 + objdiff-core/protos/diff.proto | 163 + objdiff-core/protos/proto_descriptor.bin | Bin 0 -> 15535 bytes .../protos/report.proto | 0 objdiff-core/src/arch/arm.rs | 2 +- objdiff-core/src/arch/mips.rs | 2 +- objdiff-core/src/arch/mod.rs | 2 +- objdiff-core/src/arch/ppc.rs | 2 +- objdiff-core/src/arch/x86.rs | 2 +- objdiff-core/src/bindings/diff.rs | 244 ++ objdiff-core/src/bindings/mod.rs | 4 + .../src/bindings}/report.rs | 6 + objdiff-core/src/bindings/wasm.rs | 53 + objdiff-core/src/diff/code.rs | 15 +- objdiff-core/src/diff/data.rs | 21 +- objdiff-core/src/diff/display.rs | 4 +- objdiff-core/src/diff/mod.rs | 10 + objdiff-core/src/lib.rs | 1 + objdiff-core/src/obj/mod.rs | 8 +- objdiff-core/src/obj/read.rs | 15 +- objdiff-gui/Cargo.toml | 2 +- objdiff-gui/src/app.rs | 12 +- objdiff-wasm/.gitignore | 4 + objdiff-wasm/eslint.config.js | 11 + objdiff-wasm/package-lock.json | 3519 +++++++++++++++++ objdiff-wasm/package.json | 39 + objdiff-wasm/src/main.ts | 202 + objdiff-wasm/src/worker.ts | 81 + objdiff-wasm/tsconfig.json | 8 + objdiff-wasm/tsup.config.ts | 15 + 40 files changed, 4732 insertions(+), 311 deletions(-) delete mode 100644 objdiff-cli/protos/proto_descriptor.bin create mode 100644 objdiff-cli/src/util/output.rs create mode 100644 objdiff-core/build.rs create mode 100644 objdiff-core/protos/diff.proto create mode 100644 objdiff-core/protos/proto_descriptor.bin rename {objdiff-cli => objdiff-core}/protos/report.proto (100%) create mode 100644 objdiff-core/src/bindings/diff.rs create mode 100644 objdiff-core/src/bindings/mod.rs rename {objdiff-cli/src/util => objdiff-core/src/bindings}/report.rs (97%) create mode 100644 objdiff-core/src/bindings/wasm.rs create mode 100644 objdiff-wasm/.gitignore create mode 100644 objdiff-wasm/eslint.config.js create mode 100644 objdiff-wasm/package-lock.json create mode 100644 objdiff-wasm/package.json create mode 100644 objdiff-wasm/src/main.ts create mode 100644 objdiff-wasm/src/worker.ts create mode 100644 objdiff-wasm/tsconfig.json create mode 100644 objdiff-wasm/tsup.config.ts diff --git a/Cargo.lock b/Cargo.lock index ada2bf2..fc5ccc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2825,7 +2825,7 @@ dependencies = [ [[package]] name = "objdiff-cli" -version = "2.0.0-beta.4" +version = "2.0.0-beta.5" dependencies = [ "anyhow", "argp", @@ -2833,10 +2833,7 @@ dependencies = [ "enable-ansi-support", "memmap2", "objdiff-core", - "pbjson", - "pbjson-build", "prost", - "prost-build", "ratatui", "rayon", "serde", @@ -2849,7 +2846,7 @@ dependencies = [ [[package]] name = "objdiff-core" -version = "2.0.0-beta.4" +version = "2.0.0-beta.5" dependencies = [ "anyhow", "arm-attr", @@ -2867,7 +2864,11 @@ dependencies = [ "msvc-demangler", "num-traits", "object 0.35.0", + "pbjson", + "pbjson-build", "ppc750cl", + "prost", + "prost-build", "rabbitizer", "semver", "serde", @@ -2876,11 +2877,12 @@ dependencies = [ "similar", "strum", "unarm", + "wasm-bindgen", ] [[package]] name = "objdiff-gui" -version = "2.0.0-beta.4" +version = "2.0.0-beta.5" dependencies = [ "anyhow", "bytes", @@ -4620,19 +4622,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -4657,9 +4660,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4667,9 +4670,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -4680,9 +4683,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wayland-backend" diff --git a/objdiff-cli/Cargo.toml b/objdiff-cli/Cargo.toml index 6aa7282..0067fa4 100644 --- a/objdiff-cli/Cargo.toml +++ b/objdiff-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "objdiff-cli" -version = "2.0.0-beta.4" +version = "2.0.0-beta.5" edition = "2021" rust-version = "1.70" authors = ["Luke Street "] @@ -20,7 +20,6 @@ crossterm = "0.27.0" enable-ansi-support = "0.2.1" memmap2 = "0.9.4" objdiff-core = { path = "../objdiff-core", features = ["all"] } -pbjson = "0.7.0" prost = "0.13.1" ratatui = "0.26.2" rayon = "1.10.0" @@ -30,8 +29,3 @@ supports-color = "3.0.0" time = { version = "0.3.36", features = ["formatting", "local-offset"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } - -[build-dependencies] -prost-build = "0.13.1" -pbjson-build = "0.7.0" - diff --git a/objdiff-cli/build.rs b/objdiff-cli/build.rs index 98986a6..a488c56 100644 --- a/objdiff-cli/build.rs +++ b/objdiff-cli/build.rs @@ -1,5 +1,3 @@ -use std::path::{Path, PathBuf}; - fn main() { let output = std::process::Command::new("git") .args(["rev-parse", "HEAD"]) @@ -8,55 +6,4 @@ fn main() { let rev = String::from_utf8(output.stdout).expect("Failed to parse git output"); println!("cargo:rustc-env=GIT_COMMIT_SHA={rev}"); println!("cargo:rustc-rerun-if-changed=.git/HEAD"); - - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("protos"); - let descriptor_path = root.join("proto_descriptor.bin"); - println!("cargo:rerun-if-changed={}", descriptor_path.display()); - let descriptor_mtime = std::fs::metadata(&descriptor_path) - .map(|m| m.modified().unwrap()) - .unwrap_or(std::time::SystemTime::UNIX_EPOCH); - let mut run_protoc = false; - let proto_files = vec![root.join("report.proto")]; - for proto_file in &proto_files { - println!("cargo:rerun-if-changed={}", proto_file.display()); - let mtime = match std::fs::metadata(proto_file) { - Ok(m) => m.modified().unwrap(), - Err(e) => panic!("Failed to stat proto file {}: {:?}", proto_file.display(), e), - }; - if mtime > descriptor_mtime { - run_protoc = true; - } - } - - fn prost_config(descriptor_path: &Path, run_protoc: bool) -> prost_build::Config { - let mut config = prost_build::Config::new(); - config.file_descriptor_set_path(descriptor_path); - // If our cached descriptor is up-to-date, we don't need to run protoc. - // This is helpful so that users don't need to have protoc installed - // unless they're updating the protos. - if !run_protoc { - config.skip_protoc_run(); - } - config - } - if let Err(e) = - prost_config(&descriptor_path, run_protoc).compile_protos(&proto_files, &[root.as_path()]) - { - if e.kind() == std::io::ErrorKind::NotFound && e.to_string().contains("protoc") { - eprintln!("protoc not found, skipping protobuf compilation"); - prost_config(&descriptor_path, false) - .compile_protos(&proto_files, &[root.as_path()]) - .expect("Failed to compile protos"); - } else { - panic!("Failed to compile protos: {e:?}"); - } - } - - let descriptor_set = std::fs::read(descriptor_path).expect("Failed to read descriptor set"); - pbjson_build::Builder::new() - .register_descriptors(&descriptor_set) - .expect("Failed to register descriptors") - .preserve_proto_field_names() - .build(&[".objdiff"]) - .expect("Failed to build pbjson"); } diff --git a/objdiff-cli/protos/proto_descriptor.bin b/objdiff-cli/protos/proto_descriptor.bin deleted file mode 100644 index 635b4a5cf36075b03efef6c086be49bf3ef75490..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7325 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, + #[argp(option)] + /// Output format (json, json-pretty, proto) (default: json) + format: Option, #[argp(positional)] /// Function symbol to diff - symbol: String, + symbol: Option, } pub fn run(args: Args) -> Result<()> { - let (target_path, base_path, project_config) = - match (&args.target, &args.base, &args.project, &args.unit) { - (Some(t), Some(b), None, None) => (Some(t.clone()), Some(b.clone()), None), - (None, None, p, u) => { - let project = match p { - Some(project) => project.clone(), - _ => std::env::current_dir().context("Failed to get the current directory")?, + let (target_path, base_path, project_config) = match ( + &args.target, + &args.base, + &args.project, + &args.unit, + ) { + (Some(t), Some(b), None, None) => (Some(t.clone()), Some(b.clone()), None), + (None, None, p, u) => { + let project = match p { + Some(project) => project.clone(), + _ => std::env::current_dir().context("Failed to get the current directory")?, + }; + let Some((project_config, project_config_info)) = + objdiff_core::config::try_project_config(&project) + else { + bail!("Project config not found in {}", &project.display()) + }; + let mut project_config = project_config.with_context(|| { + format!("Reading project config {}", project_config_info.path.display()) + })?; + let object = { + let resolve_paths = |o: &mut ProjectObject| { + o.resolve_paths( + &project, + project_config.target_dir.as_deref(), + project_config.base_dir.as_deref(), + ) }; - let Some((project_config, project_config_info)) = - objdiff_core::config::try_project_config(&project) - else { - bail!("Project config not found in {}", &project.display()) - }; - let mut project_config = project_config.with_context(|| { - format!("Reading project config {}", project_config_info.path.display()) - })?; - let object = { - let resolve_paths = |o: &mut ProjectObject| { - o.resolve_paths( - &project, - project_config.target_dir.as_deref(), - project_config.base_dir.as_deref(), - ) - }; - if let Some(u) = u { - let unit_path = - PathBuf::from_str(u).ok().and_then(|p| fs::canonicalize(p).ok()); - - let Some(object) = project_config.objects.iter_mut().find_map(|obj| { - if obj.name.as_deref() == Some(u) { - resolve_paths(obj); - return Some(obj); - } - - let up = unit_path.as_deref()?; + if let Some(u) = u { + let unit_path = + PathBuf::from_str(u).ok().and_then(|p| fs::canonicalize(p).ok()); + let Some(object) = project_config.objects.iter_mut().find_map(|obj| { + if obj.name.as_deref() == Some(u) { resolve_paths(obj); - - if [&obj.base_path, &obj.target_path] - .into_iter() - .filter_map(|p| p.as_ref().and_then(|p| p.canonicalize().ok())) - .any(|p| p == up) - { - return Some(obj); - } - - None - }) else { - bail!("Unit not found: {}", u) - }; - - object - } else { - let mut idx = None; - let mut count = 0usize; - for (i, obj) in project_config.objects.iter_mut().enumerate() { - resolve_paths(obj); - - if obj - .target_path - .as_deref() - .map(|o| obj::read::has_function(o, &args.symbol)) - .transpose()? - .unwrap_or(false) - { - idx = Some(i); - count += 1; - if count > 1 { - break; - } - } + return Some(obj); } - match (count, idx) { - (0, None) => bail!("Symbol not found: {}", &args.symbol), - (1, Some(i)) => &mut project_config.objects[i], - (2.., Some(_)) => bail!( - "Multiple instances of {} were found, try specifying a unit", - &args.symbol - ), - _ => unreachable!(), + + let up = unit_path.as_deref()?; + + resolve_paths(obj); + + if [&obj.base_path, &obj.target_path] + .into_iter() + .filter_map(|p| p.as_ref().and_then(|p| p.canonicalize().ok())) + .any(|p| p == up) + { + return Some(obj); + } + + None + }) else { + bail!("Unit not found: {}", u) + }; + + object + } else if let Some(symbol_name) = &args.symbol { + let mut idx = None; + let mut count = 0usize; + for (i, obj) in project_config.objects.iter_mut().enumerate() { + resolve_paths(obj); + + if obj + .target_path + .as_deref() + .map(|o| obj::read::has_function(o, symbol_name)) + .transpose()? + .unwrap_or(false) + { + idx = Some(i); + count += 1; + if count > 1 { + break; + } } } - }; - let target_path = object.target_path.clone(); - let base_path = object.base_path.clone(); - (target_path, base_path, Some(project_config)) - } - _ => bail!("Either target and base or project and unit must be specified"), - }; + match (count, idx) { + (0, None) => bail!("Symbol not found: {}", symbol_name), + (1, Some(i)) => &mut project_config.objects[i], + (2.., Some(_)) => bail!( + "Multiple instances of {} were found, try specifying a unit", + symbol_name + ), + _ => unreachable!(), + } + } else { + bail!("Must specify one of: symbol, project and unit, target and base objects") + } + }; + let target_path = object.target_path.clone(); + let base_path = object.base_path.clone(); + (target_path, base_path, Some(project_config)) + } + _ => bail!("Either target and base or project and unit must be specified"), + }; + + if let Some(output) = &args.output { + run_oneshot(&args, output, target_path.as_deref(), base_path.as_deref()) + } else { + run_interactive(args, target_path, base_path, project_config) + } +} + +fn run_oneshot( + args: &Args, + output: &Path, + target_path: Option<&Path>, + base_path: Option<&Path>, +) -> Result<()> { + let output_format = OutputFormat::from_option(args.format.as_deref())?; + let config = diff::DiffObjConfig { + relax_reloc_diffs: args.relax_reloc_diffs, + ..Default::default() // TODO + }; + let target = target_path + .map(|p| obj::read::read(p, &config).with_context(|| format!("Loading {}", p.display()))) + .transpose()?; + let base = base_path + .map(|p| obj::read::read(p, &config).with_context(|| format!("Loading {}", p.display()))) + .transpose()?; + let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), None)?; + let left = target.as_ref().and_then(|o| result.left.as_ref().map(|d| (o, d))); + let right = base.as_ref().and_then(|o| result.right.as_ref().map(|d| (o, d))); + write_output(&DiffResult::new(left, right), Some(output), output_format)?; + Ok(()) +} + +fn run_interactive( + args: Args, + target_path: Option, + base_path: Option, + project_config: Option, +) -> Result<()> { + let Some(symbol_name) = &args.symbol else { bail!("Interactive mode requires a symbol name") }; let time_format = time::format_description::parse_borrowed::<2>("[hour]:[minute]:[second]") .context("Failed to parse time format")?; let mut state = Box::new(FunctionDiffUi { @@ -156,7 +216,7 @@ pub fn run(args: Args) -> Result<()> { scroll_state_y: ScrollbarState::default(), per_page: 0, num_rows: 0, - symbol_name: args.symbol.clone(), + symbol_name: symbol_name.clone(), target_path, base_path, project_config, @@ -180,7 +240,7 @@ pub fn run(args: Args) -> Result<()> { stdout(), EnterAlternateScreen, EnableMouseCapture, - SetTitle(format!("{} - objdiff", args.symbol)), + SetTitle(format!("{} - objdiff", symbol_name)), )?; let backend = CrosstermBackend::new(stdout()); let mut terminal = Terminal::new(backend)?; @@ -814,18 +874,7 @@ impl FunctionDiffUi { let prev = self.right_obj.take(); let config = diff::DiffObjConfig { relax_reloc_diffs: self.relax_reloc_diffs, - space_between_args: true, // TODO - combine_data_sections: false, // TODO - x86_formatter: Default::default(), // TODO - mips_abi: Default::default(), // TODO - mips_instr_category: Default::default(), // TODO - arm_arch_version: Default::default(), // TODO - arm_unified_syntax: true, // TODO - arm_av_registers: false, // TODO - arm_r9_usage: Default::default(), // TODO - arm_sl_usage: false, // TODO - arm_fp_usage: false, // TODO - arm_ip_usage: false, // TODO + ..Default::default() // TODO }; let target = self .target_path diff --git a/objdiff-cli/src/cmd/report.rs b/objdiff-cli/src/cmd/report.rs index b1c8197..9b8f191 100644 --- a/objdiff-cli/src/cmd/report.rs +++ b/objdiff-cli/src/cmd/report.rs @@ -1,8 +1,7 @@ use std::{ collections::HashSet, fs::File, - io::{BufWriter, Read, Write}, - ops::DerefMut, + io::Read, path::{Path, PathBuf}, time::Instant, }; @@ -10,6 +9,10 @@ use std::{ use anyhow::{bail, Context, Result}; use argp::FromArgs; use objdiff_core::{ + bindings::report::{ + ChangeItem, ChangeItemInfo, ChangeUnit, Changes, ChangesInput, Measures, Report, + ReportItem, ReportItemMetadata, ReportUnit, ReportUnitMetadata, + }, config::ProjectObject, diff, obj, obj::{ObjSectionKind, ObjSymbolFlags}, @@ -18,13 +21,10 @@ use prost::Message; use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator}; use tracing::{info, warn}; -use crate::util::report::{ - ChangeItem, ChangeItemInfo, ChangeUnit, Changes, ChangesInput, Measures, Report, ReportItem, - ReportItemMetadata, ReportUnit, ReportUnitMetadata, -}; +use crate::util::output::{write_output, OutputFormat}; #[derive(FromArgs, PartialEq, Debug)] -/// Commands for processing NVIDIA Shield TV alf files. +/// Generate a progress report for a project. #[argp(subcommand, name = "report")] pub struct Args { #[argp(subcommand)] @@ -39,7 +39,7 @@ pub enum SubCommand { } #[derive(FromArgs, PartialEq, Debug)] -/// Generate a report from a project. +/// Generate a progress report for a project. #[argp(subcommand, name = "generate")] pub struct GenerateArgs { #[argp(option, short = 'p')] @@ -52,7 +52,7 @@ pub struct GenerateArgs { /// Deduplicate global and weak symbols (runs single-threaded) deduplicate: bool, #[argp(option, short = 'f')] - /// Output format (json or proto, default json) + /// Output format (json, json-pretty, proto) (default: json) format: Option, } @@ -70,7 +70,7 @@ pub struct ChangesArgs { /// Output file output: Option, #[argp(option, short = 'f')] - /// Output format (json or proto, default json) + /// Output format (json, json-pretty, proto) (default: json) format: Option, } @@ -81,28 +81,8 @@ pub fn run(args: Args) -> Result<()> { } } -enum OutputFormat { - Json, - Proto, -} - -impl OutputFormat { - fn from_str(s: &str) -> Result { - match s { - "json" => Ok(Self::Json), - "binpb" | "pb" | "proto" | "protobuf" => Ok(Self::Proto), - _ => bail!("Invalid output format: {}", s), - } - } -} - fn generate(args: GenerateArgs) -> Result<()> { - let output_format = if let Some(format) = &args.format { - OutputFormat::from_str(format)? - } else { - OutputFormat::Json - }; - + let output_format = OutputFormat::from_option(args.format.as_deref())?; let project_dir = args.project.as_deref().unwrap_or_else(|| Path::new(".")); info!("Loading project {}", project_dir.display()); @@ -156,45 +136,6 @@ fn generate(args: GenerateArgs) -> Result<()> { Ok(()) } -fn write_output(input: &T, output: Option<&Path>, format: OutputFormat) -> Result<()> -where T: serde::Serialize + prost::Message { - if let Some(output) = output { - info!("Writing to {}", output.display()); - let file = File::options() - .read(true) - .write(true) - .create(true) - .truncate(true) - .open(output) - .with_context(|| format!("Failed to create file {}", output.display()))?; - match format { - OutputFormat::Json => { - let mut output = BufWriter::new(file); - serde_json::to_writer_pretty(&mut output, input) - .context("Failed to write output file")?; - output.flush().context("Failed to flush output file")?; - } - OutputFormat::Proto => { - file.set_len(input.encoded_len() as u64)?; - let map = - unsafe { memmap2::Mmap::map(&file) }.context("Failed to map output file")?; - let mut output = map.make_mut().context("Failed to remap output file")?; - input.encode(&mut output.deref_mut()).context("Failed to encode output")?; - } - } - } else { - match format { - OutputFormat::Json => { - serde_json::to_writer_pretty(std::io::stdout(), input)?; - } - OutputFormat::Proto => { - std::io::stdout().write_all(&input.encode_to_vec())?; - } - } - }; - Ok(()) -} - fn report_object( object: &mut ProjectObject, project_dir: &Path, @@ -329,19 +270,8 @@ fn report_object( })) } -impl From<&ReportItem> for ChangeItemInfo { - fn from(value: &ReportItem) -> Self { - Self { fuzzy_match_percent: value.fuzzy_match_percent, size: value.size } - } -} - fn changes(args: ChangesArgs) -> Result<()> { - let output_format = if let Some(format) = &args.format { - OutputFormat::from_str(format)? - } else { - OutputFormat::Json - }; - + let output_format = OutputFormat::from_option(args.format.as_deref())?; let (previous, current) = if args.previous == Path::new("-") && args.current == Path::new("-") { // Special case for comparing two reports from stdin let mut data = vec![]; diff --git a/objdiff-cli/src/main.rs b/objdiff-cli/src/main.rs index b131fcb..7a5acf0 100644 --- a/objdiff-cli/src/main.rs +++ b/objdiff-cli/src/main.rs @@ -54,7 +54,7 @@ impl FromArgValue for LogLevel { } #[derive(FromArgs, PartialEq, Debug)] -/// Yet another GameCube/Wii decompilation toolkit. +/// A local diffing tool for decompilation projects. struct TopLevel { #[argp(subcommand)] command: SubCommand, diff --git a/objdiff-cli/src/util/mod.rs b/objdiff-cli/src/util/mod.rs index 1f743a1..82c2d3d 100644 --- a/objdiff-cli/src/util/mod.rs +++ b/objdiff-cli/src/util/mod.rs @@ -1,2 +1,2 @@ -pub mod report; +pub mod output; pub mod term; diff --git a/objdiff-cli/src/util/output.rs b/objdiff-cli/src/util/output.rs new file mode 100644 index 0000000..8651aee --- /dev/null +++ b/objdiff-cli/src/util/output.rs @@ -0,0 +1,84 @@ +use std::{ + fs::File, + io::{BufWriter, Write}, + ops::DerefMut, + path::Path, +}; + +use anyhow::{bail, Context, Result}; +use tracing::info; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +pub enum OutputFormat { + #[default] + Json, + JsonPretty, + Proto, +} + +impl OutputFormat { + pub fn from_str(s: &str) -> Result { + match s.to_ascii_lowercase().as_str() { + "json" => Ok(Self::Json), + "json-pretty" | "json_pretty" => Ok(Self::JsonPretty), + "binpb" | "pb" | "proto" | "protobuf" => Ok(Self::Proto), + _ => bail!("Invalid output format: {}", s), + } + } + + pub fn from_option(s: Option<&str>) -> Result { + match s { + Some(s) => Self::from_str(s), + None => Ok(Self::default()), + } + } +} + +pub fn write_output(input: &T, output: Option<&Path>, format: OutputFormat) -> Result<()> +where T: serde::Serialize + prost::Message { + match output { + Some(output) if output != Path::new("-") => { + info!("Writing to {}", output.display()); + let file = File::options() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(output) + .with_context(|| format!("Failed to create file {}", output.display()))?; + match format { + OutputFormat::Json => { + let mut output = BufWriter::new(file); + serde_json::to_writer(&mut output, input) + .context("Failed to write output file")?; + output.flush().context("Failed to flush output file")?; + } + OutputFormat::JsonPretty => { + let mut output = BufWriter::new(file); + serde_json::to_writer_pretty(&mut output, input) + .context("Failed to write output file")?; + output.flush().context("Failed to flush output file")?; + } + OutputFormat::Proto => { + file.set_len(input.encoded_len() as u64)?; + let map = unsafe { memmap2::Mmap::map(&file) } + .context("Failed to map output file")?; + let mut output = map.make_mut().context("Failed to remap output file")?; + input.encode(&mut output.deref_mut()).context("Failed to encode output")?; + } + } + } + _ => match format { + OutputFormat::Json => { + serde_json::to_writer(std::io::stdout(), input)?; + } + OutputFormat::JsonPretty => { + serde_json::to_writer_pretty(std::io::stdout(), input)?; + } + OutputFormat::Proto => { + std::io::stdout().write_all(&input.encode_to_vec())?; + } + }, + } + Ok(()) +} diff --git a/objdiff-core/Cargo.toml b/objdiff-core/Cargo.toml index e2860e6..605f559 100644 --- a/objdiff-core/Cargo.toml +++ b/objdiff-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "objdiff-core" -version = "2.0.0-beta.4" +version = "2.0.0-beta.5" edition = "2021" rust-version = "1.70" authors = ["Luke Street "] @@ -11,6 +11,9 @@ description = """ A local diffing tool for decompilation projects. """ +[lib] +crate-type = ["cdylib", "rlib"] + [features] all = ["config", "dwarf", "mips", "ppc", "x86", "arm"] any-arch = [] # Implicit, used to check if any arch is enabled @@ -20,6 +23,7 @@ mips = ["any-arch", "rabbitizer"] ppc = ["any-arch", "cwdemangle", "cwextab", "ppc750cl"] x86 = ["any-arch", "cpp_demangle", "iced-x86", "msvc-demangler"] arm = ["any-arch", "cpp_demangle", "unarm", "arm-attr"] +wasm = ["serde_json"] [dependencies] anyhow = "1.0.82" @@ -30,9 +34,12 @@ log = "0.4.21" memmap2 = "0.9.4" num-traits = "0.2.18" object = { version = "0.35.0", features = ["read_core", "std", "elf", "pe"], default-features = false } +pbjson = "0.7.0" +prost = "0.13.1" serde = { version = "1", features = ["derive"] } similar = { version = "2.5.0", default-features = false } strum = { version = "0.26.2", features = ["derive"] } +wasm-bindgen = "0.2.93" # config globset = { version = "0.4.14", features = ["serde1"], optional = true } @@ -59,3 +66,7 @@ msvc-demangler = { version = "0.10.0", optional = true } # arm unarm = { version = "1.4.0", optional = true } arm-attr = { version = "0.1.1", optional = true } + +[build-dependencies] +prost-build = "0.13.1" +pbjson-build = "0.7.0" diff --git a/objdiff-core/build.rs b/objdiff-core/build.rs new file mode 100644 index 0000000..5f0864c --- /dev/null +++ b/objdiff-core/build.rs @@ -0,0 +1,54 @@ +use std::path::{Path, PathBuf}; + +fn main() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("protos"); + let descriptor_path = root.join("proto_descriptor.bin"); + println!("cargo:rerun-if-changed={}", descriptor_path.display()); + let descriptor_mtime = std::fs::metadata(&descriptor_path) + .map(|m| m.modified().unwrap()) + .unwrap_or(std::time::SystemTime::UNIX_EPOCH); + let mut run_protoc = false; + let proto_files = vec![root.join("diff.proto"), root.join("report.proto")]; + for proto_file in &proto_files { + println!("cargo:rerun-if-changed={}", proto_file.display()); + let mtime = match std::fs::metadata(proto_file) { + Ok(m) => m.modified().unwrap(), + Err(e) => panic!("Failed to stat proto file {}: {:?}", proto_file.display(), e), + }; + if mtime > descriptor_mtime { + run_protoc = true; + } + } + + fn prost_config(descriptor_path: &Path, run_protoc: bool) -> prost_build::Config { + let mut config = prost_build::Config::new(); + config.file_descriptor_set_path(descriptor_path); + // If our cached descriptor is up-to-date, we don't need to run protoc. + // This is helpful so that users don't need to have protoc installed + // unless they're updating the protos. + if !run_protoc { + config.skip_protoc_run(); + } + config + } + if let Err(e) = + prost_config(&descriptor_path, run_protoc).compile_protos(&proto_files, &[root.as_path()]) + { + if e.kind() == std::io::ErrorKind::NotFound && e.to_string().contains("protoc") { + eprintln!("protoc not found, skipping protobuf compilation"); + prost_config(&descriptor_path, false) + .compile_protos(&proto_files, &[root.as_path()]) + .expect("Failed to compile protos"); + } else { + panic!("Failed to compile protos: {e:?}"); + } + } + + let descriptor_set = std::fs::read(descriptor_path).expect("Failed to read descriptor set"); + pbjson_build::Builder::new() + .register_descriptors(&descriptor_set) + .expect("Failed to register descriptors") + .preserve_proto_field_names() + .build(&[".objdiff"]) + .expect("Failed to build pbjson"); +} diff --git a/objdiff-core/protos/diff.proto b/objdiff-core/protos/diff.proto new file mode 100644 index 0000000..bd91287 --- /dev/null +++ b/objdiff-core/protos/diff.proto @@ -0,0 +1,163 @@ +syntax = "proto3"; + +package objdiff.diff; + +// A symbol +message Symbol { + // Name of the symbol + string name = 1; + // Demangled name of the symbol + optional string demangled_name = 2; + // Symbol address + uint64 address = 3; + // Symbol size + uint64 size = 4; + // Bitmask of SymbolFlag + uint32 flags = 5; +} + +// Symbol visibility flags +enum SymbolFlag { + SYMBOL_NONE = 0; + SYMBOL_GLOBAL = 1; + SYMBOL_LOCAL = 2; + SYMBOL_WEAK = 3; + SYMBOL_COMMON = 4; + SYMBOL_HIDDEN = 5; +} + +// A single parsed instruction +message Instruction { + // Instruction address + uint64 address = 1; + // Instruction size + uint32 size = 2; + // Instruction opcode + uint32 opcode = 3; + // Instruction mnemonic + string mnemonic = 4; + // Instruction formatted string + string formatted = 5; + // Original (unsimplified) instruction string + optional string original = 6; + // Instruction arguments + repeated Argument arguments = 7; + // Instruction relocation + optional Relocation relocation = 8; + // Instruction branch destination + optional uint64 branch_dest = 9; + // Instruction line number + optional uint32 line_number = 10; +} + +// An instruction argument +message Argument { + oneof value { + // Plain text + string plain_text = 1; + // Value + ArgumentValue argument = 2; + // Relocation + ArgumentRelocation relocation = 3; + // Branch destination + uint64 branch_dest = 4; + } +} + +// An instruction argument value +message ArgumentValue { + oneof value { + // Signed integer + int64 signed = 1; + // Unsigned integer + uint64 unsigned = 2; + // Opaque value + string opaque = 3; + } +} + +// Marker type for relocation arguments +message ArgumentRelocation { +} + +message Relocation { + uint32 type = 1; + string type_name = 2; + RelocationTarget target = 3; +} + +message RelocationTarget { + Symbol symbol = 1; + int64 addend = 2; +} + +message InstructionDiff { + DiffKind diff_kind = 1; + optional Instruction instruction = 2; + optional InstructionBranchFrom branch_from = 3; + optional InstructionBranchTo branch_to = 4; + repeated ArgumentDiff arg_diff = 5; +} + +message ArgumentDiff { + optional uint32 diff_index = 1; +} + +enum DiffKind { + DIFF_NONE = 0; + DIFF_REPLACE = 1; + DIFF_DELETE = 2; + DIFF_INSERT = 3; + DIFF_OP_MISMATCH = 4; + DIFF_ARG_MISMATCH = 5; +} + +message InstructionBranchFrom { + repeated uint32 instruction_index = 1; + uint32 branch_index = 2; +} + +message InstructionBranchTo { + uint32 instruction_index = 1; + uint32 branch_index = 2; +} + +message FunctionDiff { + Symbol symbol = 1; + repeated InstructionDiff instructions = 2; + optional float match_percent = 3; +} + +message DataDiff { + DiffKind kind = 1; + bytes data = 2; + // May be larger than data + uint64 size = 3; +} + +message SectionDiff { + string name = 1; + SectionKind kind = 2; + uint64 size = 3; + uint64 address = 4; + repeated FunctionDiff functions = 5; + repeated DataDiff data = 6; + optional float match_percent = 7; +} + +enum SectionKind { + SECTION_UNKNOWN = 0; + SECTION_TEXT = 1; + SECTION_DATA = 2; + SECTION_BSS = 3; + SECTION_COMMON = 4; +} + +message ObjectDiff { + repeated SectionDiff sections = 1; +} + +message DiffResult { + optional ObjectDiff left = 1; + optional ObjectDiff right = 2; +} diff --git a/objdiff-core/protos/proto_descriptor.bin b/objdiff-core/protos/proto_descriptor.bin new file mode 100644 index 0000000000000000000000000000000000000000..46866c0324f0bb9d9c505e66293158f04a01b580 GIT binary patch literal 15535 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 j34VrR?Kf}1bZ@NDpP{&Gi, + line_info: &BTreeMap, config: &DiffObjConfig, ) -> Result { let start_addr = address as u32; diff --git a/objdiff-core/src/arch/mips.rs b/objdiff-core/src/arch/mips.rs index 60fe14b..aca016d 100644 --- a/objdiff-core/src/arch/mips.rs +++ b/objdiff-core/src/arch/mips.rs @@ -85,7 +85,7 @@ impl ObjArch for ObjArchMips { code: &[u8], _section_index: usize, relocations: &[ObjReloc], - line_info: &BTreeMap, + line_info: &BTreeMap, config: &DiffObjConfig, ) -> Result { let _guard = RABBITIZER_MUTEX.lock().map_err(|e| anyhow!("Failed to lock mutex: {e}"))?; diff --git a/objdiff-core/src/arch/mod.rs b/objdiff-core/src/arch/mod.rs index 8f838e5..ee62bb0 100644 --- a/objdiff-core/src/arch/mod.rs +++ b/objdiff-core/src/arch/mod.rs @@ -24,7 +24,7 @@ pub trait ObjArch: Send + Sync { code: &[u8], section_index: usize, relocations: &[ObjReloc], - line_info: &BTreeMap, + line_info: &BTreeMap, config: &DiffObjConfig, ) -> Result; diff --git a/objdiff-core/src/arch/ppc.rs b/objdiff-core/src/arch/ppc.rs index fa252b8..ff65773 100644 --- a/objdiff-core/src/arch/ppc.rs +++ b/objdiff-core/src/arch/ppc.rs @@ -35,7 +35,7 @@ impl ObjArch for ObjArchPpc { code: &[u8], _section_index: usize, relocations: &[ObjReloc], - line_info: &BTreeMap, + line_info: &BTreeMap, config: &DiffObjConfig, ) -> Result { let ins_count = code.len() / 4; diff --git a/objdiff-core/src/arch/x86.rs b/objdiff-core/src/arch/x86.rs index a35c987..ca4d171 100644 --- a/objdiff-core/src/arch/x86.rs +++ b/objdiff-core/src/arch/x86.rs @@ -32,7 +32,7 @@ impl ObjArch for ObjArchX86 { code: &[u8], _section_index: usize, relocations: &[ObjReloc], - line_info: &BTreeMap, + line_info: &BTreeMap, config: &DiffObjConfig, ) -> Result { let mut result = ProcessCodeResult { ops: Vec::new(), insts: Vec::new() }; diff --git a/objdiff-core/src/bindings/diff.rs b/objdiff-core/src/bindings/diff.rs new file mode 100644 index 0000000..b29105f --- /dev/null +++ b/objdiff-core/src/bindings/diff.rs @@ -0,0 +1,244 @@ +use crate::{ + diff::{ + ObjDataDiff, ObjDataDiffKind, ObjDiff, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, + ObjInsDiff, ObjInsDiffKind, ObjSectionDiff, ObjSymbolDiff, + }, + obj::{ + ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSectionKind, ObjSymbol, + ObjSymbolFlagSet, ObjSymbolFlags, + }, +}; + +// Protobuf diff types +include!(concat!(env!("OUT_DIR"), "/objdiff.diff.rs")); +include!(concat!(env!("OUT_DIR"), "/objdiff.diff.serde.rs")); + +impl DiffResult { + pub fn new(left: Option<(&ObjInfo, &ObjDiff)>, right: Option<(&ObjInfo, &ObjDiff)>) -> Self { + Self { + left: left.map(|(obj, diff)| ObjectDiff::new(obj, diff)), + right: right.map(|(obj, diff)| ObjectDiff::new(obj, diff)), + } + } +} + +impl ObjectDiff { + pub fn new(obj: &ObjInfo, diff: &ObjDiff) -> Self { + Self { + sections: diff + .sections + .iter() + .enumerate() + .map(|(i, d)| SectionDiff::new(obj, i, d)) + .collect(), + } + } +} + +impl SectionDiff { + pub fn new(obj: &ObjInfo, section_index: usize, section_diff: &ObjSectionDiff) -> Self { + let section = &obj.sections[section_index]; + let functions = section_diff.symbols.iter().map(|d| FunctionDiff::new(obj, d)).collect(); + let data = section_diff.data_diff.iter().map(|d| DataDiff::new(obj, d)).collect(); + Self { + name: section.name.to_string(), + kind: SectionKind::from(section.kind) as i32, + size: section.size, + address: section.address, + functions, + data, + match_percent: section_diff.match_percent, + } + } +} + +impl From for SectionKind { + fn from(value: ObjSectionKind) -> Self { + match value { + ObjSectionKind::Code => SectionKind::SectionText, + ObjSectionKind::Data => SectionKind::SectionData, + ObjSectionKind::Bss => SectionKind::SectionBss, + // TODO common + } + } +} + +impl FunctionDiff { + pub fn new(object: &ObjInfo, symbol_diff: &ObjSymbolDiff) -> Self { + let (_section, symbol) = object.section_symbol(symbol_diff.symbol_ref); + // let diff_symbol = symbol_diff.diff_symbol.map(|symbol_ref| { + // let (_section, symbol) = object.section_symbol(symbol_ref); + // Symbol::from(symbol) + // }); + let instructions = symbol_diff.instructions.iter().map(InstructionDiff::from).collect(); + Self { + symbol: Some(Symbol::from(symbol)), + // diff_symbol, + instructions, + match_percent: symbol_diff.match_percent, + } + } +} + +impl DataDiff { + pub fn new(_object: &ObjInfo, data_diff: &ObjDataDiff) -> Self { + Self { + kind: DiffKind::from(data_diff.kind) as i32, + data: data_diff.data.clone(), + size: data_diff.len as u64, + } + } +} + +impl<'a> From<&'a ObjSymbol> for Symbol { + fn from(value: &'a ObjSymbol) -> Self { + Self { + name: value.name.to_string(), + demangled_name: value.demangled_name.clone(), + address: value.address, + size: value.size, + flags: symbol_flags(value.flags), + } + } +} + +fn symbol_flags(value: ObjSymbolFlagSet) -> u32 { + let mut flags = 0u32; + if value.0.contains(ObjSymbolFlags::Global) { + flags |= SymbolFlag::SymbolNone as u32; + } + if value.0.contains(ObjSymbolFlags::Local) { + flags |= SymbolFlag::SymbolLocal as u32; + } + if value.0.contains(ObjSymbolFlags::Weak) { + flags |= SymbolFlag::SymbolWeak as u32; + } + if value.0.contains(ObjSymbolFlags::Common) { + flags |= SymbolFlag::SymbolCommon as u32; + } + if value.0.contains(ObjSymbolFlags::Hidden) { + flags |= SymbolFlag::SymbolHidden as u32; + } + flags +} + +impl<'a> From<&'a ObjIns> for Instruction { + fn from(value: &'a ObjIns) -> Self { + Self { + address: value.address, + size: value.size as u32, + opcode: value.op as u32, + mnemonic: value.mnemonic.clone(), + formatted: value.formatted.clone(), + arguments: value.args.iter().map(Argument::from).collect(), + relocation: value.reloc.as_ref().map(Relocation::from), + branch_dest: value.branch_dest, + line_number: value.line, + original: value.orig.clone(), + } + } +} + +impl<'a> From<&'a ObjInsArg> for Argument { + fn from(value: &'a ObjInsArg) -> Self { + Self { + value: Some(match value { + ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()), + ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::from(v)), + ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}), + ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest), + }), + } + } +} + +impl From<&ObjInsArgValue> for ArgumentValue { + fn from(value: &ObjInsArgValue) -> Self { + Self { + value: Some(match value { + ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v), + ObjInsArgValue::Unsigned(v) => argument_value::Value::Unsigned(*v), + ObjInsArgValue::Opaque(v) => argument_value::Value::Opaque(v.to_string()), + }), + } + } +} + +impl<'a> From<&'a ObjReloc> for Relocation { + fn from(value: &ObjReloc) -> Self { + Self { + r#type: match value.flags { + object::RelocationFlags::Elf { r_type } => r_type, + object::RelocationFlags::MachO { r_type, .. } => r_type as u32, + object::RelocationFlags::Coff { typ } => typ as u32, + object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32, + _ => unreachable!(), + }, + type_name: String::new(), // TODO + target: Some(RelocationTarget::from(&value.target)), + } + } +} + +impl<'a> From<&'a ObjSymbol> for RelocationTarget { + fn from(value: &'a ObjSymbol) -> Self { + Self { symbol: Some(Symbol::from(value)), addend: value.addend } + } +} + +impl<'a> From<&'a ObjInsDiff> for InstructionDiff { + fn from(value: &'a ObjInsDiff) -> Self { + Self { + instruction: value.ins.as_ref().map(Instruction::from), + diff_kind: DiffKind::from(value.kind) as i32, + branch_from: value.branch_from.as_ref().map(InstructionBranchFrom::from), + branch_to: value.branch_to.as_ref().map(InstructionBranchTo::from), + arg_diff: value.arg_diff.iter().map(ArgumentDiff::from).collect(), + } + } +} + +impl From<&Option> for ArgumentDiff { + fn from(value: &Option) -> Self { + Self { diff_index: value.as_ref().map(|v| v.idx as u32) } + } +} + +impl From for DiffKind { + fn from(value: ObjInsDiffKind) -> Self { + match value { + ObjInsDiffKind::None => DiffKind::DiffNone, + ObjInsDiffKind::OpMismatch => DiffKind::DiffOpMismatch, + ObjInsDiffKind::ArgMismatch => DiffKind::DiffArgMismatch, + ObjInsDiffKind::Replace => DiffKind::DiffReplace, + ObjInsDiffKind::Delete => DiffKind::DiffDelete, + ObjInsDiffKind::Insert => DiffKind::DiffInsert, + } + } +} + +impl From for DiffKind { + fn from(value: ObjDataDiffKind) -> Self { + match value { + ObjDataDiffKind::None => DiffKind::DiffNone, + ObjDataDiffKind::Replace => DiffKind::DiffReplace, + ObjDataDiffKind::Delete => DiffKind::DiffDelete, + ObjDataDiffKind::Insert => DiffKind::DiffInsert, + } + } +} + +impl<'a> From<&'a ObjInsBranchFrom> for InstructionBranchFrom { + fn from(value: &'a ObjInsBranchFrom) -> Self { + Self { + instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(), + branch_index: value.branch_idx as u32, + } + } +} + +impl<'a> From<&'a ObjInsBranchTo> for InstructionBranchTo { + fn from(value: &'a ObjInsBranchTo) -> Self { + Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 } + } +} diff --git a/objdiff-core/src/bindings/mod.rs b/objdiff-core/src/bindings/mod.rs new file mode 100644 index 0000000..3eea4e2 --- /dev/null +++ b/objdiff-core/src/bindings/mod.rs @@ -0,0 +1,4 @@ +pub mod diff; +pub mod report; +#[cfg(feature = "wasm")] +pub mod wasm; diff --git a/objdiff-cli/src/util/report.rs b/objdiff-core/src/bindings/report.rs similarity index 97% rename from objdiff-cli/src/util/report.rs rename to objdiff-core/src/bindings/report.rs index ecba347..8b4488b 100644 --- a/objdiff-cli/src/util/report.rs +++ b/objdiff-core/src/bindings/report.rs @@ -69,6 +69,12 @@ impl Measures { } } +impl From<&ReportItem> for ChangeItemInfo { + fn from(value: &ReportItem) -> Self { + Self { fuzzy_match_percent: value.fuzzy_match_percent, size: value.size } + } +} + /// Allows [collect](Iterator::collect) to be used on an iterator of [Measures]. impl FromIterator for Measures { fn from_iter(iter: T) -> Self diff --git a/objdiff-core/src/bindings/wasm.rs b/objdiff-core/src/bindings/wasm.rs new file mode 100644 index 0000000..0ed4bc9 --- /dev/null +++ b/objdiff-core/src/bindings/wasm.rs @@ -0,0 +1,53 @@ +use anyhow::Context; +use prost::Message; +use wasm_bindgen::prelude::*; + +use crate::{bindings::diff::DiffResult, diff, obj}; + +#[wasm_bindgen] +pub fn run_diff( + left: Option>, + right: Option>, + config: diff::DiffObjConfig, +) -> Result { + let target = left + .as_ref() + .map(|data| obj::read::parse(data, &config).context("Loading target")) + .transpose() + .map_err(|e| JsError::new(&e.to_string()))?; + let base = right + .as_ref() + .map(|data| obj::read::parse(data, &config).context("Loading base")) + .transpose() + .map_err(|e| JsError::new(&e.to_string()))?; + let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), None) + .map_err(|e| JsError::new(&e.to_string()))?; + let left = target.as_ref().and_then(|o| result.left.as_ref().map(|d| (o, d))); + let right = base.as_ref().and_then(|o| result.right.as_ref().map(|d| (o, d))); + let out = DiffResult::new(left, right); + serde_json::to_string(&out).map_err(|e| JsError::new(&e.to_string())) +} + +#[wasm_bindgen] +pub fn run_diff_proto( + left: Option>, + right: Option>, + config: diff::DiffObjConfig, +) -> Result, JsError> { + let target = left + .as_ref() + .map(|data| obj::read::parse(data, &config).context("Loading target")) + .transpose() + .map_err(|e| JsError::new(&e.to_string()))?; + let base = right + .as_ref() + .map(|data| obj::read::parse(data, &config).context("Loading base")) + .transpose() + .map_err(|e| JsError::new(&e.to_string()))?; + let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), None) + .map_err(|e| JsError::new(&e.to_string()))?; + let left = target.as_ref().and_then(|o| result.left.as_ref().map(|d| (o, d))); + let right = base.as_ref().and_then(|o| result.right.as_ref().map(|d| (o, d))); + let out = DiffResult::new(left, right); + Ok(out.encode_to_vec().into_boxed_slice()) +} diff --git a/objdiff-core/src/diff/code.rs b/objdiff-core/src/diff/code.rs index 8297cc8..8e99bd5 100644 --- a/objdiff-core/src/diff/code.rs +++ b/objdiff-core/src/diff/code.rs @@ -1,8 +1,4 @@ -use std::{ - cmp::max, - collections::BTreeMap, - time::{Duration, Instant}, -}; +use std::{cmp::max, collections::BTreeMap}; use anyhow::{anyhow, Result}; use similar::{capture_diff_slices_deadline, Algorithm}; @@ -100,13 +96,8 @@ fn diff_instructions( left_code: &ProcessCodeResult, right_code: &ProcessCodeResult, ) -> Result<()> { - let deadline = Instant::now() + Duration::from_secs(5); - let ops = capture_diff_slices_deadline( - Algorithm::Patience, - &left_code.ops, - &right_code.ops, - Some(deadline), - ); + let ops = + capture_diff_slices_deadline(Algorithm::Patience, &left_code.ops, &right_code.ops, None); if ops.is_empty() { left_diff.extend( left_code diff --git a/objdiff-core/src/diff/data.rs b/objdiff-core/src/diff/data.rs index c429dcb..4498bff 100644 --- a/objdiff-core/src/diff/data.rs +++ b/objdiff-core/src/diff/data.rs @@ -1,7 +1,4 @@ -use std::{ - cmp::{max, min, Ordering}, - time::{Duration, Instant}, -}; +use std::cmp::{max, min, Ordering}; use anyhow::{anyhow, Result}; use similar::{capture_diff_slices_deadline, get_diff_ratio, Algorithm}; @@ -47,15 +44,13 @@ pub fn diff_data_section( left_section_diff: &ObjSectionDiff, right_section_diff: &ObjSectionDiff, ) -> Result<(ObjSectionDiff, ObjSectionDiff)> { - let deadline = Instant::now() + Duration::from_secs(5); let left_max = left.symbols.iter().map(|s| s.section_address + s.size).max().unwrap_or(0).min(left.size); let right_max = right.symbols.iter().map(|s| s.section_address + s.size).max().unwrap_or(0).min(right.size); let left_data = &left.data[..left_max as usize]; let right_data = &right.data[..right_max as usize]; - let ops = - capture_diff_slices_deadline(Algorithm::Patience, left_data, right_data, Some(deadline)); + let ops = capture_diff_slices_deadline(Algorithm::Patience, left_data, right_data, None); let match_percent = get_diff_ratio(&ops, left_data.len(), right_data.len()) * 100.0; let mut left_diff = Vec::::new(); @@ -157,9 +152,7 @@ pub fn diff_data_symbol( let right_data = &right_section.data[right_symbol.section_address as usize ..(right_symbol.section_address + right_symbol.size) as usize]; - let deadline = Instant::now() + Duration::from_secs(5); - let ops = - capture_diff_slices_deadline(Algorithm::Patience, left_data, right_data, Some(deadline)); + let ops = capture_diff_slices_deadline(Algorithm::Patience, left_data, right_data, None); let match_percent = get_diff_ratio(&ops, left_data.len(), right_data.len()) * 100.0; Ok(( @@ -209,15 +202,9 @@ pub fn diff_bss_section( left_diff: &ObjSectionDiff, right_diff: &ObjSectionDiff, ) -> Result<(ObjSectionDiff, ObjSectionDiff)> { - let deadline = Instant::now() + Duration::from_secs(5); let left_sizes = left.symbols.iter().map(|s| (s.section_address, s.size)).collect::>(); let right_sizes = right.symbols.iter().map(|s| (s.section_address, s.size)).collect::>(); - let ops = capture_diff_slices_deadline( - Algorithm::Patience, - &left_sizes, - &right_sizes, - Some(deadline), - ); + let ops = capture_diff_slices_deadline(Algorithm::Patience, &left_sizes, &right_sizes, None); let mut match_percent = get_diff_ratio(&ops, left_sizes.len(), right_sizes.len()) * 100.0; // Use the highest match percent between two options: diff --git a/objdiff-core/src/diff/display.rs b/objdiff-core/src/diff/display.rs index 6f007bd..40a1ad4 100644 --- a/objdiff-core/src/diff/display.rs +++ b/objdiff-core/src/diff/display.rs @@ -12,7 +12,7 @@ pub enum DiffText<'a> { /// Colored text BasicColor(&'a str, usize), /// Line number - Line(usize), + Line(u32), /// Instruction address Address(u64), /// Instruction mnemonic @@ -49,7 +49,7 @@ pub fn display_diff( return Ok(()); }; if let Some(line) = ins.line { - cb(DiffText::Line(line as usize))?; + cb(DiffText::Line(line))?; } cb(DiffText::Address(ins.address - base_addr))?; if let Some(branch) = &ins_diff.branch_from { diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index 5be8611..a87ff78 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -1,6 +1,7 @@ use std::collections::HashSet; use anyhow::Result; +use wasm_bindgen::prelude::wasm_bindgen; use crate::{ diff::{ @@ -17,6 +18,7 @@ pub mod code; pub mod data; pub mod display; +#[wasm_bindgen] #[derive( Debug, Copy, @@ -41,6 +43,7 @@ pub enum X86Formatter { Masm, } +#[wasm_bindgen] #[derive( Debug, Copy, @@ -65,6 +68,7 @@ pub enum MipsAbi { N64, } +#[wasm_bindgen] #[derive( Debug, Copy, @@ -93,6 +97,7 @@ pub enum MipsInstrCategory { R5900, } +#[wasm_bindgen] #[derive( Debug, Copy, @@ -117,6 +122,7 @@ pub enum ArmArchVersion { V6K, } +#[wasm_bindgen] #[derive( Debug, Copy, @@ -148,6 +154,7 @@ pub enum ArmR9Usage { #[inline] const fn default_true() -> bool { true } +#[wasm_bindgen] #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct DiffObjConfig { @@ -200,6 +207,9 @@ impl DiffObjConfig { } } +#[wasm_bindgen] +pub fn default_diff_obj_config() -> DiffObjConfig { Default::default() } + #[derive(Debug, Clone)] pub struct ObjSectionDiff { pub symbols: Vec, diff --git a/objdiff-core/src/lib.rs b/objdiff-core/src/lib.rs index 7d8e77d..48f1e72 100644 --- a/objdiff-core/src/lib.rs +++ b/objdiff-core/src/lib.rs @@ -1,4 +1,5 @@ pub mod arch; +pub mod bindings; #[cfg(feature = "config")] pub mod config; pub mod diff; diff --git a/objdiff-core/src/obj/mod.rs b/objdiff-core/src/obj/mod.rs index 128b536..8e69024 100644 --- a/objdiff-core/src/obj/mod.rs +++ b/objdiff-core/src/obj/mod.rs @@ -41,7 +41,7 @@ pub struct ObjSection { pub relocations: Vec, pub virtual_address: Option, /// Line number info (.line or .debug_line section) - pub line_info: BTreeMap, + pub line_info: BTreeMap, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -103,7 +103,7 @@ pub struct ObjIns { pub reloc: Option, pub branch_dest: Option, /// Line number - pub line: Option, + pub line: Option, /// Formatted instruction pub formatted: String, /// Original (unsimplified) instruction @@ -136,8 +136,8 @@ pub struct ObjExtab { pub struct ObjInfo { pub arch: Box, - pub path: PathBuf, - pub timestamp: FileTime, + pub path: Option, + pub timestamp: Option, pub sections: Vec, /// Common BSS symbols pub common: Vec, diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index bc1e550..689ad54 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -426,7 +426,7 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> { }; let end = start + size as u64; while reader.position() < end { - let line_number = read_u32(obj_file, &mut reader)? as u64; + let line_number = read_u32(obj_file, &mut reader)?; let statement_pos = read_u16(obj_file, &mut reader)?; if statement_pos != 0xFFFF { log::warn!("Unhandled statement pos {}", statement_pos); @@ -468,7 +468,7 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> { let mut rows = program.rows(); while let Some((_header, row)) = rows.next_row()? { if let (Some(line), Some(lines)) = (row.line(), &mut lines) { - lines.insert(row.address(), line.get()); + lines.insert(row.address(), line.get() as u32); } if row.end_sequence() { // The next row is the start of a new sequence, which means we must @@ -600,7 +600,14 @@ pub fn read(obj_path: &Path, config: &DiffObjConfig) -> Result { let timestamp = FileTime::from_last_modification_time(&file.metadata()?); (unsafe { memmap2::Mmap::map(&file) }?, timestamp) }; - let obj_file = File::parse(&*data)?; + let mut obj = parse(&data, config)?; + obj.path = Some(obj_path.to_owned()); + obj.timestamp = Some(timestamp); + Ok(obj) +} + +pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result { + let obj_file = File::parse(data)?; let arch = new_arch(&obj_file)?; let split_meta = split_meta(&obj_file)?; let mut sections = filter_sections(&obj_file, split_meta.as_ref())?; @@ -616,7 +623,7 @@ pub fn read(obj_path: &Path, config: &DiffObjConfig) -> Result { line_info(&obj_file, &mut sections)?; let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?; let extab = exception_tables(&mut sections, &obj_file)?; - Ok(ObjInfo { arch, path: obj_path.to_owned(), timestamp, sections, common, extab, split_meta }) + Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, extab, split_meta }) } pub fn has_function(obj_path: &Path, symbol_name: &str) -> Result { diff --git a/objdiff-gui/Cargo.toml b/objdiff-gui/Cargo.toml index 540c6c9..e6e62f9 100644 --- a/objdiff-gui/Cargo.toml +++ b/objdiff-gui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "objdiff-gui" -version = "2.0.0-beta.4" +version = "2.0.0-beta.5" edition = "2021" rust-version = "1.70" authors = ["Luke Street "] diff --git a/objdiff-gui/src/app.rs b/objdiff-gui/src/app.rs index fae0e10..9382cd1 100644 --- a/objdiff-gui/src/app.rs +++ b/objdiff-gui/src/app.rs @@ -401,13 +401,17 @@ impl App { if let Some(result) = &diff_state.build { if let Some((obj, _)) = &result.first_obj { - if file_modified(&obj.path, obj.timestamp) { - config.queue_reload = true; + if let (Some(path), Some(timestamp)) = (&obj.path, obj.timestamp) { + if file_modified(path, timestamp) { + config.queue_reload = true; + } } } if let Some((obj, _)) = &result.second_obj { - if file_modified(&obj.path, obj.timestamp) { - config.queue_reload = true; + if let (Some(path), Some(timestamp)) = (&obj.path, obj.timestamp) { + if file_modified(path, timestamp) { + config.queue_reload = true; + } } } } diff --git a/objdiff-wasm/.gitignore b/objdiff-wasm/.gitignore new file mode 100644 index 0000000..184b70b --- /dev/null +++ b/objdiff-wasm/.gitignore @@ -0,0 +1,4 @@ +dist/ +gen/ +node_modules/ +pkg/ diff --git a/objdiff-wasm/eslint.config.js b/objdiff-wasm/eslint.config.js new file mode 100644 index 0000000..d00320c --- /dev/null +++ b/objdiff-wasm/eslint.config.js @@ -0,0 +1,11 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; + +export default [ + {files: ["**/*.{js,mjs,cjs,ts}"]}, + {languageOptions: {globals: globals.browser}}, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + {rules: {"semi": [2, "always"]}}, +]; \ No newline at end of file diff --git a/objdiff-wasm/package-lock.json b/objdiff-wasm/package-lock.json new file mode 100644 index 0000000..d920662 --- /dev/null +++ b/objdiff-wasm/package-lock.json @@ -0,0 +1,3519 @@ +{ + "name": "objdiff-wasm", + "version": "2.0.0-beta.6", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "objdiff-wasm", + "version": "2.0.0-beta.6", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "2.9.4" + }, + "devDependencies": { + "@eslint/js": "^9.9.0", + "@protobuf-ts/plugin": "2.9.4", + "@types/node": "22.4.1", + "esbuild": "0.23.1", + "eslint": "^9.9.0", + "globals": "^15.9.0", + "tsup": "8.2.4", + "typescript-eslint": "^8.2.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", + "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobuf-ts/plugin": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.9.4.tgz", + "integrity": "sha512-Db5Laq5T3mc6ERZvhIhkj1rn57/p8gbWiCKxQWbZBBl20wMuqKoHbRw4tuD7FyXi+IkwTToaNVXymv5CY3E8Rw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/plugin-framework": "^2.9.4", + "@protobuf-ts/protoc": "^2.9.4", + "@protobuf-ts/runtime": "^2.9.4", + "@protobuf-ts/runtime-rpc": "^2.9.4", + "typescript": "^3.9" + }, + "bin": { + "protoc-gen-dump": "bin/protoc-gen-dump", + "protoc-gen-ts": "bin/protoc-gen-ts" + } + }, + "node_modules/@protobuf-ts/plugin-framework": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.9.4.tgz", + "integrity": "sha512-9nuX1kjdMliv+Pes8dQCKyVhjKgNNfwxVHg+tx3fLXSfZZRcUHMc1PMwB9/vTvc6gBKt9QGz5ERqSqZc0++E9A==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)", + "dependencies": { + "@protobuf-ts/runtime": "^2.9.4", + "typescript": "^3.9" + } + }, + "node_modules/@protobuf-ts/plugin-framework/node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@protobuf-ts/plugin/node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@protobuf-ts/protoc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.9.4.tgz", + "integrity": "sha512-hQX+nOhFtrA+YdAXsXEDrLoGJqXHpgv4+BueYF0S9hy/Jq0VRTVlJS1Etmf4qlMt/WdigEes5LOd/LDzui4GIQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "protoc": "protoc.js" + } + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.9.4.tgz", + "integrity": "sha512-vHRFWtJJB/SiogWDF0ypoKfRIZ41Kq+G9cEFj6Qm1eQaAhJ1LDFvgZ7Ja4tb3iLOQhz0PaoPnnOijF1qmEqTxg==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.9.4.tgz", + "integrity": "sha512-y9L9JgnZxXFqH5vD4d7j9duWvIJ7AShyBRoNKJGhu9Q27qIbchfzli66H9RvrQNIFk5ER7z1Twe059WZGqERcA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.9.4" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz", + "integrity": "sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz", + "integrity": "sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz", + "integrity": "sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz", + "integrity": "sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz", + "integrity": "sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz", + "integrity": "sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz", + "integrity": "sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz", + "integrity": "sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz", + "integrity": "sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz", + "integrity": "sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz", + "integrity": "sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz", + "integrity": "sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz", + "integrity": "sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz", + "integrity": "sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz", + "integrity": "sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz", + "integrity": "sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.4.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.1.tgz", + "integrity": "sha512-1tbpb9325+gPnKK0dMm+/LMriX0vKxf6RnB0SZUqfyVkQ4fMgUSySqhxE/y8Jvs4NyF1yHzTfG9KlnkIODxPKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.2.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bundle-require": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.0.0.tgz", + "integrity": "sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", + "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz", + "integrity": "sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.21.0", + "@rollup/rollup-android-arm64": "4.21.0", + "@rollup/rollup-darwin-arm64": "4.21.0", + "@rollup/rollup-darwin-x64": "4.21.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.0", + "@rollup/rollup-linux-arm-musleabihf": "4.21.0", + "@rollup/rollup-linux-arm64-gnu": "4.21.0", + "@rollup/rollup-linux-arm64-musl": "4.21.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.0", + "@rollup/rollup-linux-riscv64-gnu": "4.21.0", + "@rollup/rollup-linux-s390x-gnu": "4.21.0", + "@rollup/rollup-linux-x64-gnu": "4.21.0", + "@rollup/rollup-linux-x64-musl": "4.21.0", + "@rollup/rollup-win32-arm64-msvc": "4.21.0", + "@rollup/rollup-win32-ia32-msvc": "4.21.0", + "@rollup/rollup-win32-x64-msvc": "4.21.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tsup": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.2.4.tgz", + "integrity": "sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.0.0", + "cac": "^6.7.14", + "chokidar": "^3.6.0", + "consola": "^3.2.3", + "debug": "^4.3.5", + "esbuild": "^0.23.0", + "execa": "^5.1.1", + "globby": "^11.1.0", + "joycon": "^3.1.1", + "picocolors": "^1.0.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.19.0", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.2.0.tgz", + "integrity": "sha512-DmnqaPcML0xYwUzgNbM1XaKXpEb7BShYf2P1tkUmmcl8hyeG7Pj08Er7R9bNy6AufabywzJcOybQAtnD/c9DGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", + "@typescript-eslint/utils": "8.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/objdiff-wasm/package.json b/objdiff-wasm/package.json new file mode 100644 index 0000000..4b9decf --- /dev/null +++ b/objdiff-wasm/package.json @@ -0,0 +1,39 @@ +{ + "name": "objdiff-wasm", + "version": "2.0.0-beta.6", + "description": "A local diffing tool for decompilation projects.", + "author": { + "name": "Luke Street", + "email": "luke@street.dev" + }, + "license": "MIT OR Apache-2.0", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/encounter/objdiff.git" + }, + "files": [ + "dist/*" + ], + "main": "dist/main.js", + "types": "dist/main.d.ts", + "scripts": { + "build": "tsup", + "build:all": "npm run build && npm run build:proto && npm run build:wasm", + "build:proto": "protoc --ts_out=gen --ts_opt add_pb_suffix,eslint_disable,ts_nocheck,use_proto_field_name --proto_path=../objdiff-core/protos ../objdiff-core/protos/*.proto", + "build:wasm": "cd ../objdiff-core && wasm-pack build --out-dir ../objdiff-wasm/pkg --target web -- --features arm,dwarf,ppc,x86,wasm" + }, + "dependencies": { + "@protobuf-ts/runtime": "2.9.4" + }, + "devDependencies": { + "@eslint/js": "^9.9.0", + "@protobuf-ts/plugin": "2.9.4", + "@types/node": "22.4.1", + "esbuild": "0.23.1", + "eslint": "^9.9.0", + "globals": "^15.9.0", + "tsup": "8.2.4", + "typescript-eslint": "^8.2.0" + } +} diff --git a/objdiff-wasm/src/main.ts b/objdiff-wasm/src/main.ts new file mode 100644 index 0000000..6aab965 --- /dev/null +++ b/objdiff-wasm/src/main.ts @@ -0,0 +1,202 @@ +import {ArgumentValue, DiffResult, InstructionDiff, RelocationTarget} from "../gen/diff_pb"; +import type { + ArmArchVersion, + ArmR9Usage, + DiffObjConfig as WasmDiffObjConfig, + MipsAbi, + MipsInstrCategory, + X86Formatter +} from '../pkg'; +import {InMessage, OutMessage} from './worker'; + +// Export wasm types +export type DiffObjConfig = Omit, 'free'>; +export {ArmArchVersion, ArmR9Usage, MipsAbi, MipsInstrCategory, X86Formatter}; + +// Export protobuf types +export * from '../gen/diff_pb'; + +interface PromiseCallbacks { + start: number; + resolve: (value: unknown) => void; + reject: (reason?: unknown) => void; +} + +let workerInit = false; +let workerCallbacks: PromiseCallbacks | null = null; +const workerReady = new Promise((resolve, reject) => { + workerCallbacks = {start: performance.now(), resolve, reject}; +}); + +export function initialize(workerUrl?: string | URL) { + if (workerInit) { + return; + } + workerInit = true; + const worker = new Worker(workerUrl || 'worker.js', {type: 'module'}); + worker.onmessage = onMessage.bind(null, worker); + worker.onerror = (error) => { + console.error("Worker error", error); + workerCallbacks.reject(error); + }; +} + +let globalMessageId = 0; +const messageCallbacks = new Map(); + +function onMessage(worker: Worker, event: MessageEvent) { + switch (event.data.type) { + case 'ready': + workerCallbacks.resolve(worker); + break; + case 'result': { + const {messageId, result} = event.data; + const callbacks = messageCallbacks.get(messageId); + if (callbacks) { + const end = performance.now(); + console.debug(`Message ${messageId} took ${end - callbacks.start}ms`); + messageCallbacks.delete(messageId); + callbacks.resolve(result); + } else { + console.warn(`Unknown message ID ${messageId}`); + } + break; + } + } +} + +async function defer(message: Omit): Promise { + if (!workerInit) { + throw new Error('Worker not initialized'); + } + const worker = await workerReady; + const messageId = globalMessageId++; + const promise = new Promise((resolve, reject) => { + messageCallbacks.set(messageId, {start: performance.now(), resolve, reject}); + }); + worker.postMessage({ + ...message, + messageId + }); + return promise; +} + +export async function runDiff(left: Uint8Array | undefined, right: Uint8Array | undefined, config?: DiffObjConfig): Promise { + const data = await defer({ + type: 'run_diff', + left, + right, + config + } as InMessage); + const parseStart = performance.now(); + const result = DiffResult.fromBinary(data, {readUnknownField: false}); + const end = performance.now(); + console.debug(`Parsing message took ${end - parseStart}ms`); + return result; +} + +export type DiffText = + DiffTextBasic + | DiffTextBasicColor + | DiffTextAddress + | DiffTextLine + | DiffTextOpcode + | DiffTextArgument + | DiffTextSymbol + | DiffTextBranchDest + | DiffTextSpacing; + +type DiffTextBase = { + diff_index?: number, +}; +export type DiffTextBasic = DiffTextBase & { + type: 'basic', + text: string, +}; +export type DiffTextBasicColor = DiffTextBase & { + type: 'basic_color', + text: string, + index: number, +}; +export type DiffTextAddress = DiffTextBase & { + type: 'address', + address: bigint, +}; +export type DiffTextLine = DiffTextBase & { + type: 'line', + line_number: number, +}; +export type DiffTextOpcode = DiffTextBase & { + type: 'opcode', + mnemonic: string, + opcode: number, +}; +export type DiffTextArgument = DiffTextBase & { + type: 'argument', + value: ArgumentValue, +}; +export type DiffTextSymbol = DiffTextBase & { + type: 'symbol', + target: RelocationTarget, +}; +export type DiffTextBranchDest = DiffTextBase & { + type: 'branch_dest', + address: bigint, +}; +export type DiffTextSpacing = DiffTextBase & { + type: 'spacing', + count: number, +}; + +// TypeScript workaround for oneof types +export function oneof(type: T): T & { oneofKind: string } { + return type as T & { oneofKind: string }; +} + +// Native JavaScript implementation of objdiff_core::diff::display::display_diff +export function displayDiff(diff: InstructionDiff, baseAddr: bigint, cb: (text: DiffText) => void) { + const ins = diff.instruction; + if (!ins) { + return; + } + if (ins.line_number != null) { + cb({type: 'line', line_number: ins.line_number}); + } + cb({type: 'address', address: ins.address - baseAddr}); + if (diff.branch_from) { + cb({type: 'basic_color', text: ' ~> ', index: diff.branch_from.branch_index}); + } else { + cb({type: 'spacing', count: 4}); + } + cb({type: 'opcode', mnemonic: ins.mnemonic, opcode: ins.opcode}); + for (let i = 0; i < ins.arguments.length; i++) { + if (i === 0) { + cb({type: 'spacing', count: 1}); + } + const arg = oneof(ins.arguments[i].value); + const diff_index = diff.arg_diff[i]?.diff_index; + switch (arg.oneofKind) { + case "plain_text": + cb({type: 'basic', text: arg.plain_text, diff_index}); + break; + case "argument": + cb({type: 'argument', value: arg.argument, diff_index}); + break; + case "relocation": { + const reloc = ins.relocation!; + cb({type: 'symbol', target: reloc.target, diff_index}); + break; + } + case "branch_dest": + if (arg.branch_dest < baseAddr) { + cb({type: 'basic', text: '', diff_index}); + } else { + cb({type: 'branch_dest', address: arg.branch_dest - baseAddr, diff_index}); + } + break; + } + } + if (diff.branch_to) { + cb({type: 'basic_color', text: ' ~> ', index: diff.branch_to.branch_index}); + } +} diff --git a/objdiff-wasm/src/worker.ts b/objdiff-wasm/src/worker.ts new file mode 100644 index 0000000..3dacce9 --- /dev/null +++ b/objdiff-wasm/src/worker.ts @@ -0,0 +1,81 @@ +import wasmInit, {default_diff_obj_config, run_diff_proto} from '../pkg'; +import {DiffObjConfig} from "./main"; + +self.postMessage({type: 'init'} as OutMessage); +await wasmInit({}); +self.postMessage({type: 'ready'} as OutMessage); + +type ExtractParam = { + [K in keyof T]: T[K] extends (arg1: infer U, ...args: any[]) => any ? U & { type: K } : never; +}[keyof T]; +type HandlerData = ExtractParam<{ + run_diff: typeof run_diff, +}>; +const handlers: { + [K in HandlerData['type']]: (data: Omit) => unknown +} = { + 'run_diff': run_diff, +}; + +function run_diff({left, right, config}: { + left: Uint8Array | undefined, + right: Uint8Array | undefined, + config?: DiffObjConfig +}): Uint8Array { + const cfg = default_diff_obj_config(); + if (config) { + for (const key in config) { + if (key in config) { + cfg[key] = config[key]; + } + } + } + return run_diff_proto(left, right, cfg); +} + +export type InMessage = HandlerData & { messageId: number }; + +export type OutMessage = ({ + type: 'result', + result: unknown | null, + error: unknown | null, +} | { + type: 'init', + msg: string +} | { + type: 'ready', + msg: string +}) & { messageId: number }; + +self.onmessage = async (event: MessageEvent) => { + const data = event.data; + const handler = handlers[data.type]; + if (handler) { + try { + const start = performance.now(); + const result = handler(data); + const end = performance.now(); + console.debug(`Worker message ${data.messageId} took ${end - start}ms`); + self.postMessage({ + type: 'result', + result: result, + error: null, + messageId: data.messageId + }); + } catch (error) { + self.postMessage({ + type: 'result', + result: null, + error: error, + messageId: data.messageId + }); + } + } else { + self.postMessage({ + type: 'result', + result: null, + error: `No handler for ${data.type}`, + messageId: data.messageId + }); + } +}; diff --git a/objdiff-wasm/tsconfig.json b/objdiff-wasm/tsconfig.json new file mode 100644 index 0000000..16f1f56 --- /dev/null +++ b/objdiff-wasm/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "ES2022", + "moduleResolution": "Node", + "target": "ES2022", + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/objdiff-wasm/tsup.config.ts b/objdiff-wasm/tsup.config.ts new file mode 100644 index 0000000..02a8fbb --- /dev/null +++ b/objdiff-wasm/tsup.config.ts @@ -0,0 +1,15 @@ +import {defineConfig} from 'tsup'; +import fs from 'node:fs/promises'; + +export default defineConfig({ + entry: ['src/main.ts', 'src/worker.ts'], + clean: true, + dts: true, + format: 'esm', + sourcemap: true, + splitting: false, + target: ['es2022', 'chrome89', 'edge89', 'firefox89', 'safari15', 'node14.8'], + async onSuccess() { + await fs.copyFile('pkg/objdiff_core_bg.wasm', 'dist/objdiff_core_bg.wasm'); + } +});