Skip to content

Commit

Permalink
refactor(js): remove double wrap (#1138)
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra authored Mar 5, 2025
1 parent 8a92bb7 commit c765a53
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 325 deletions.
28 changes: 1 addition & 27 deletions js-rattler/crate/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
mod error;
mod gateway;
mod parse_strictness;
pub mod solve;
mod utils;
mod version;
mod version_spec;

pub use error::{JsError, JsResult};
use rattler_conda_types::ParseStrictness;

use wasm_bindgen::prelude::*;

Expand All @@ -21,29 +21,3 @@ static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
pub fn start() {
utils::set_panic_hook();
}

/// Defines how strict a parser should be when parsing an object from a string.
/// @public
#[wasm_bindgen(js_name=ParseStrictness)]
pub enum JsParseStrictness {
Strict,
Lenient,
}

impl From<ParseStrictness> for JsParseStrictness {
fn from(value: ParseStrictness) -> Self {
match value {
ParseStrictness::Strict => JsParseStrictness::Strict,
ParseStrictness::Lenient => JsParseStrictness::Lenient,
}
}
}

impl From<JsParseStrictness> for ParseStrictness {
fn from(value: JsParseStrictness) -> Self {
match value {
JsParseStrictness::Strict => ParseStrictness::Strict,
JsParseStrictness::Lenient => ParseStrictness::Lenient,
}
}
}
37 changes: 37 additions & 0 deletions js-rattler/crate/parse_strictness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use rattler_conda_types::ParseStrictness;
use serde::Deserialize;
use wasm_bindgen::prelude::wasm_bindgen;

#[wasm_bindgen(typescript_custom_section)]
const PARSE_STRICTNESS_TS: &'static str = r#"
/**
* Defines how strict a parser should be when parsing an object from a string.
*
* @public
*/
export type ParseStrictness = "strict" | "lenient";
"#;

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = "ParseStrictness", typescript_type = "ParseStrictness")]
pub type JsParseStrictness;
}

impl TryFrom<JsParseStrictness> for ParseStrictness {
type Error = serde_wasm_bindgen::Error;

fn try_from(value: JsParseStrictness) -> Result<Self, Self::Error> {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EnumNames {
Strict,
Lenient,
}

match serde_wasm_bindgen::from_value(value.obj)? {
EnumNames::Strict => Ok(ParseStrictness::Strict),
EnumNames::Lenient => Ok(ParseStrictness::Lenient),
}
}
}
157 changes: 128 additions & 29 deletions js-rattler/crate/version.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
use crate::JsResult;
use rattler_conda_types::{Version, VersionBumpType};
use std::{cmp::Ordering, str::FromStr};
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsValue;

use crate::JsResult;

#[wasm_bindgen]
/// This class implements an order relation between version strings. Version
/// strings can contain the usual alphanumeric characters (A-Za-z0-9), separated
/// into segments by dots and underscores. Empty segments (i.e. two consecutive
/// dots, a leading/trailing underscore) are not permitted. An optional epoch
/// number - an integer followed by '!' - can precede the actual version string
/// (this is useful to indicate a change in the versioning scheme itself).
/// Version comparison is case-insensitive.
///
/// @public
#[wasm_bindgen(js_name = "Version")]
#[repr(transparent)]
#[derive(Eq, PartialEq)]
pub struct JsVersion {
Expand All @@ -28,110 +39,198 @@ impl AsRef<Version> for JsVersion {
}
}

#[wasm_bindgen]
pub struct MajorMinor(pub usize, pub usize);

#[wasm_bindgen]
#[wasm_bindgen(js_class = "Version")]
impl JsVersion {
/// Constructs a new Version object from a string representation.
#[wasm_bindgen(constructor)]
pub fn new(version: &str) -> JsResult<Self> {
pub fn new(
#[wasm_bindgen(param_description = "The string representation of the version.")]
version: &str,
) -> JsResult<Self> {
let version = Version::from_str(version)?;
Ok(version.into())
}

/// Returns the string representation of the version.
///
/// An attempt is made to return the version in the same format as the input
/// string but this is not guaranteed.
#[wasm_bindgen(js_name = "toString")]
pub fn as_str(&self) -> String {
format!("{}", self.as_ref())
}

/// The epoch part of the version. E.g. `1` in `1!2.3`.
#[wasm_bindgen(getter)]
pub fn epoch(&self) -> Option<usize> {
self.as_ref().epoch_opt().map(|v| v as usize)
}

#[wasm_bindgen(getter)]
/// `true` if the version has a local part. E.g. `2.3` in `1+2.3`.
#[wasm_bindgen(getter, js_name = "hasLocal")]
pub fn has_local(&self) -> bool {
self.as_ref().has_local()
}

#[wasm_bindgen(getter)]
/// `true` if the version is considered a development version.
///
/// A development version is a version that contains the string `dev` in the
/// version string.
#[wasm_bindgen(getter, js_name = "isDev")]
pub fn is_dev(&self) -> bool {
self.as_ref().is_dev()
}

pub fn as_major_minor(&self) -> Option<MajorMinor> {
/// Returns the major and minor part of the version if the version does not
/// represent a typical major minor version. If any of the parts are not a
/// single number, undefined is returned.
// TODO: Simplify when https://github.com/rustwasm/wasm-bindgen/issues/122 is fixed
#[wasm_bindgen(
js_name = "asMajorMinor",
unchecked_return_type = "[number, number] | undefined"
)]
pub fn as_major_minor(&self) -> Option<Vec<JsValue>> {
let (major, minor) = self.as_ref().as_major_minor()?;
Some(MajorMinor(major as _, minor as _))
}

pub fn starts_with(&self, other: &Self) -> bool {
Some(vec![
JsValue::from(major as usize),
JsValue::from(minor as usize),
])
}

/// Returns true if this version starts with the other version. This is
/// defined as the other version being a prefix of this version.
#[wasm_bindgen(js_name = "startsWith")]
pub fn starts_with(
&self,
#[wasm_bindgen(param_description = "The version to use for the comparison")] other: &Self,
) -> bool {
self.as_ref().starts_with(other.as_ref())
}

pub fn compatible_with(&self, other: &Self) -> bool {
/// Returns true if this version is compatible with the other version.
#[wasm_bindgen(js_name = "compatibleWith")]
pub fn compatible_with(
&self,
#[wasm_bindgen(param_description = "The version to use for the comparison")] other: &Self,
) -> bool {
self.as_ref().compatible_with(other.as_ref())
}

pub fn pop_segments(&self, n: usize) -> Option<Self> {
/// Pop the last `n` segments from the version.
#[wasm_bindgen(js_name = "popSegments")]
pub fn pop_segments(
&self,
#[wasm_bindgen(param_description = "The number of segments to pop")] n: usize,
) -> Option<Self> {
Some(self.as_ref().pop_segments(n)?.into())
}

pub fn extend_to_length(&self, length: usize) -> JsResult<Self> {
/// Extend the version to the given length by adding zeros. If the version
/// is already at the specified length or longer the original version
/// will be returned.
#[wasm_bindgen(js_name = "extendToLength")]
pub fn extend_to_length(
&self,
#[wasm_bindgen(param_description = "The length to extend to")] length: usize,
) -> JsResult<Self> {
Ok(self.as_ref().extend_to_length(length)?.into_owned().into())
}

pub fn with_segments(&self, start: usize, stop: usize) -> Option<Self> {
let range = start..stop;
/// Returns a new version with the segments from start to end (exclusive).
///
/// Returns undefined if the start or end index is out of bounds.
#[wasm_bindgen(js_name = "withSegments")]
pub fn with_segments(
&self,
#[wasm_bindgen(param_description = "The start index")] start: usize,
#[wasm_bindgen(param_description = "The end index")] end: usize,
) -> Option<Self> {
let range = start..end;
Some(self.as_ref().with_segments(range)?.into())
}

/// The number of segments in the version.
#[wasm_bindgen(getter)]
pub fn length(&self) -> usize {
self.as_ref().segment_count()
}

/// Create a new version with local segment stripped.
/// Returns the version without the local part. E.g. `1+2.3` becomes `1`.
#[wasm_bindgen(js_name = "stripLocal")]
pub fn strip_local(&self) -> Self {
self.as_ref().strip_local().into_owned().into()
}

/// Returns a new version where the major segment of this version has been bumped.
/// Returns a new version where the major segment of this version has been
/// bumped.
#[wasm_bindgen(js_name = "bumpMajor")]
pub fn bump_major(&self) -> JsResult<Self> {
Ok(self.as_ref().bump(VersionBumpType::Major).map(Into::into)?)
}

/// Returns a new version where the minor segment of this version has been bumped.
/// Returns a new version where the minor segment of this version has been
/// bumped.
#[wasm_bindgen(js_name = "bumpMinor")]
pub fn bump_minor(&self) -> JsResult<Self> {
Ok(self.as_ref().bump(VersionBumpType::Minor).map(Into::into)?)
}

/// Returns a new version where the patch segment of this version has been bumped.
/// Returns a new version where the patch segment of this version has been
/// bumped.
#[wasm_bindgen(js_name = "bumpPatch")]
pub fn bump_patch(&self) -> JsResult<Self> {
Ok(self.as_ref().bump(VersionBumpType::Patch).map(Into::into)?)
}

/// Returns a new version where the last segment of this version has been bumped.
/// Returns a new version where the last segment of this version has been
/// bumped.
#[wasm_bindgen(js_name = "bumpLast")]
pub fn bump_last(&self) -> JsResult<Self> {
Ok(self.as_ref().bump(VersionBumpType::Last).map(Into::into)?)
}

/// Returns a new version where the given segment of this version has been bumped.
pub fn bump_segment(&self, index: i32) -> JsResult<Self> {
/// Returns a new version where the given segment of this version has been
/// bumped.
#[wasm_bindgen(js_name = "bumpSegment")]
pub fn bump_segment(
&self,
#[wasm_bindgen(param_description = "The index of the segment to bump")] index: i32,
) -> JsResult<Self> {
Ok(self
.as_ref()
.bump(VersionBumpType::Segment(index))
.map(Into::into)?)
}

/// Returns a new version where the last segment is an "alpha" segment (ie. `.0a0`)
/// Returns a new version where the last segment is an "alpha" segment (ie.
/// `.0a0`)
#[wasm_bindgen(js_name = "withAlpha")]
pub fn with_alpha(&self) -> Self {
self.as_ref().with_alpha().into_owned().into()
}

pub fn equals(&self, other: &Self) -> bool {
/// Compares this version with another version. Returns `true` if the
/// versions are considered equal.
///
/// Note that two version strings can be considered equal even if they are
/// not exactly the same. For example, `1.0` and `1` are considered equal.
#[wasm_bindgen(js_name = "equals")]
pub fn equals(
&self,
#[wasm_bindgen(param_description = "The version to compare with")] other: &Self,
) -> bool {
self.as_ref() == other.as_ref()
}

pub fn compare(&self, other: &Self) -> i8 {
/// Compare two versions.
///
/// Returns `-1` if this instance should be ordered before `other`, `0` if
/// this version and `other` are considered equal, `1` if this version
/// should be ordered after `other`.
pub fn compare(
&self,
#[wasm_bindgen(param_description = "The version to compare with")] other: &Self,
) -> i8 {
match self.as_ref().cmp(other.as_ref()) {
Ordering::Less => -1,
Ordering::Equal => 0,
Expand Down
37 changes: 29 additions & 8 deletions js-rattler/crate/version_spec.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use crate::version::JsVersion;
use crate::{JsParseStrictness, JsResult};
use rattler_conda_types::VersionSpec;
use rattler_conda_types::{ParseStrictness, VersionSpec};
use wasm_bindgen::prelude::wasm_bindgen;

#[wasm_bindgen]
use crate::parse_strictness::JsParseStrictness;
use crate::{version::JsVersion, JsResult};

/// Represents a version specification in the conda ecosystem.
///
/// @public
#[wasm_bindgen(js_name = "VersionSpec")]
#[repr(transparent)]
#[derive(Eq, PartialEq)]
pub struct JsVersionSpec {
Expand All @@ -28,19 +32,36 @@ impl AsRef<VersionSpec> for JsVersionSpec {
}
}

#[wasm_bindgen]
#[wasm_bindgen(js_class = "VersionSpec")]
impl JsVersionSpec {
/// Constructs a new VersionSpec object from a string representation.
#[wasm_bindgen(constructor)]
pub fn new(version_spec: &str, parse_strictness: JsParseStrictness) -> JsResult<Self> {
let spec = VersionSpec::from_str(version_spec, parse_strictness.into())?;
pub fn new(
#[wasm_bindgen(param_description = "The string representation of the version spec.")]
version_spec: &str,
#[wasm_bindgen(param_description = "The strictness of the parser.")]
parse_strictness: Option<JsParseStrictness>,
) -> JsResult<Self> {
let parse_strictness = parse_strictness
.map(TryFrom::try_from)
.transpose()?
.unwrap_or(ParseStrictness::Lenient);

let spec = VersionSpec::from_str(version_spec, parse_strictness)?;
Ok(spec.into())
}

/// Returns the string representation of the version spec.
#[wasm_bindgen(js_name = "toString")]
pub fn as_str(&self) -> String {
format!("{}", self.as_ref())
}

pub fn matches(&self, version: &JsVersion) -> bool {
/// Returns true if the version matches this version spec.
pub fn matches(
&self,
#[wasm_bindgen(param_description = "The version to match")] version: &JsVersion,
) -> bool {
self.as_ref().matches(version.as_ref())
}
}
Loading

0 comments on commit c765a53

Please sign in to comment.