@csaf-rs/vers-like-specifier 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  [![crates.io](https://img.shields.io/crates/v/vers-like-specifier.svg)](https://crates.io/crates/vers-like-specifier)
4
4
  [![npm](https://img.shields.io/npm/v/%40csaf-rs%2Fvers-like-specifier.svg)](https://www.npmjs.com/package/@csaf-rs/vers-like-specifier)
5
5
 
6
- A Rust library for parsing and validating **Vers-like Specifiers** (vls) as defined in [CSAF 2.0](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#31232-branches-type---name-under-product-version-range) and [CSAF 2.1](https://docs.oasis-open.org/csaf/csaf/v2.1/csaf-v2.1.html#branches-type---name-under-product-version-range).
6
+ A Rust library for parsing and validating **VERS-like Specifiers** (vls) as defined in [CSAF 2.0](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#31232-branches-type---name-under-product-version-range) and [CSAF 2.1](https://docs.oasis-open.org/csaf/csaf/v2.1/csaf-v2.1.html#branches-type---name-under-product-version-range).
7
7
 
8
- vers-like-specifier is the `<constraints>` portion of a [vers](https://github.com/package-url/vers-spec) URL **without** the `vers:<type>/` prefix.
8
+ VERS-like specifier is the `<constraints>` portion of a [VERS](https://github.com/package-url/vers-spec) URL **without** the `vers:<type>/` prefix.
9
9
 
10
10
  It represents a `|`-separated list of constraints each consisting of an implicit or explicit comparator and a version string.
11
11
 
12
- **Due to the undefined / unknown schema, it is nearly impossible for tools to reliably determine whether a given version is in the range or not. vls is a fallback option and SHOULD NOT be used unless really necessary.**
12
+ **Due to the undefined / unknown VERS type, it is nearly impossible for tools to reliably determine whether a given version is in the range or not. vls is a fallback option and SHOULD NOT be used unless really necessary.**
13
13
 
14
14
  ## Minimum Supported Rust Version (MSRV)
15
15
 
@@ -27,7 +27,7 @@ vers-like-specifier = "0.1"
27
27
  ## Usage
28
28
 
29
29
  ```rust
30
- use vers_like_specifier::{Vls, Comparator};
30
+ use vers_like_specifier::{Vls, Comparator, Containment};
31
31
 
32
32
  let vls: Vls = ">=1.0.0|<2.0.0".parse().unwrap();
33
33
  assert_eq!(vls.constraints().len(), 2);
@@ -39,28 +39,41 @@ assert_eq!(constraints[0].comparator(), &Comparator::GreaterThanOrEqual);
39
39
  assert_eq!(constraints[0].version().to_string(), "1.0.0");
40
40
  assert_eq!(constraints[1].comparator(), &Comparator::LessThan);
41
41
  assert_eq!(constraints[1].version().to_string(), "2.0.0");
42
+
43
+ // Because the VERS type is unknown, `contains` can only resolve a definite
44
+ // answer when a version exactly matches a constraint; otherwise it is `Undetermined`.
45
+ assert_eq!(vls.contains("1.0.0"), Containment::Contained);
46
+ assert_eq!(vls.contains("2.0.0"), Containment::NotContained);
47
+ assert_eq!(vls.contains("1.5.0"), Containment::Undetermined);
48
+
49
+ // The one exception: a vls pinning a single version is always decidable, since
50
+ // containment then reduces to a plain string comparison.
51
+ let pinned: Vls = "1.0.0".parse().unwrap();
52
+ assert_eq!(pinned.contains("1.0.0"), Containment::Contained);
53
+ assert_eq!(pinned.contains("2.0.0"), Containment::NotContained);
42
54
  ```
43
55
 
44
56
  ### JavaScript / WASM Usage
45
57
 
46
58
  ```js
47
- import init, { Vls, Constraint, Comparator } from "@csaf-rs/vers-like-specifier";
59
+ import init, { Vls, Constraint, Comparator, Containment } from "@csaf-rs/vers-like-specifier";
48
60
 
49
61
  await init();
50
62
 
51
63
  const vls = Vls.parse(">=1.0.0|<2.0.0");
52
64
  console.log(vls.isSingleVersion()); // false
53
65
 
54
- const single = Vls.parse("=1.0.0");
55
- console.log(single.isSingleVersion()); // true
56
-
57
66
  const constraint = new Constraint(Comparator.GreaterThanOrEqual, "1.0.0");
58
67
  console.log(constraint.version); // "1.0.0"
59
68
 
69
+ console.log(vls.contains("1.0.0") === Containment.Contained); // true (matches the >= constraint exactly)
70
+ console.log(vls.contains("2.0.0") === Containment.NotContained); // true (2.0.0 < 2.0.0 is always false)
71
+ console.log(vls.contains("1.5.0") === Containment.Undetermined); // true (can't be resolved; VERS type is unknown)
72
+
60
73
  try {
61
74
  Vls.parse("*");
62
75
  } catch (e) {
63
- console.error(e); // Error: '*' (vers syntax for matching all versions) is not allowed as a vls string
76
+ console.error(e); // Error: '*' (VERS syntax for matching all versions) is not allowed as a vls string
64
77
  }
65
78
  ```
66
79
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@csaf-rs/vers-like-specifier",
3
3
  "type": "module",
4
4
  "description": "vls (vers-like specifier) parser",
5
- "version": "0.1.2",
5
+ "version": "0.1.3",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -16,7 +16,7 @@ export type ConstraintError = "EmptyConstraint" | "EmptyConstraintVersion" | { I
16
16
  /**
17
17
  * Errors that can occur when parsing a vls string.
18
18
  */
19
- export type VlsError = "EmptyInput" | "ForbiddenAnyUsed" | { InvalidCharacters: string[] } | "ContainsVersPrefix" | "ContainsVersType" | { InvalidConstraints: ConstraintError[] } | { DuplicateConstraintVersions: string[] } | { Serialization: string };
19
+ export type VlsError = "EmptyInput" | "ForbiddenAnyUsed" | { InvalidCharacters: string[] } | { InvalidConstraints: ConstraintError[] } | { DuplicateConstraintVersions: string[] } | { Serialization: string };
20
20
 
21
21
 
22
22
  /**
@@ -79,9 +79,47 @@ export class Constraint {
79
79
  }
80
80
 
81
81
  /**
82
- * A **Vers-like Specifier** (VLS).
82
+ * The result of a containment check performed by [`Vls::contains`].
83
+ *
84
+ * Because the VERS type of a [`Vls`] is unspecified, containment can usually only be
85
+ * resolved when the queried version exactly matches a constraint's version:
86
+ *
87
+ * * [`Comparator::Equal`], [`Comparator::GreaterThanOrEqual`], [`Comparator::LessThanOrEqual`]:
88
+ * an exact match means the version is contained (`x = x`, `x >= x`, `x <= x` all hold) →
89
+ * [`Containment::Contained`].
90
+ * * [`Comparator::NotEqual`], [`Comparator::LessThan`], [`Comparator::GreaterThan`]:
91
+ * an exact match means the version is explicitly not contained (`x != x`, `x < x`, `x > x`
92
+ * are always false) → [`Containment::NotContained`].
93
+ * * No constraint's version matches exactly: containment cannot be resolved, as the VERS
94
+ * type is unknown / unspecified → [`Containment::Undetermined`].
95
+ *
96
+ * The one exception is a [`Vls`] that pins a single version (see [`Vls::is_single_version`]):
97
+ * since it has exactly one [`Comparator::Equal`] constraint, containment reduces to a plain
98
+ * string comparison and is always decidable, regardless of VERS type. In that case,
99
+ * *any* queried version resolves to either [`Containment::Contained`] or
100
+ * [`Containment::NotContained`], never [`Containment::Undetermined`].
101
+ */
102
+ export enum Containment {
103
+ /**
104
+ * The version is contained in the specifier.
105
+ */
106
+ Contained = 0,
107
+ /**
108
+ * The version is explicitly not contained in the specifier.
109
+ */
110
+ NotContained = 1,
111
+ /**
112
+ * Containment could not be determined: the version does not exactly match any
113
+ * constraint, and the (unspecified) VERS type does not allow any further
114
+ * comparison.
115
+ */
116
+ Undetermined = 2,
117
+ }
118
+
119
+ /**
120
+ * A **VERS-like specifier** (vls).
83
121
  *
84
- * VLS is the `<constraints>` part of a [vers](https://github.com/package-url/vers-spec)
122
+ * vls is the `<constraints>` part of a [VERS](https://github.com/package-url/vers-spec)
85
123
  * URL *without* the `vers:<type>/` prefix.
86
124
  *
87
125
  * It is an ordered, `|`-separated list of [`Constraint`] values.
@@ -93,30 +131,14 @@ export class Constraint {
93
131
  *
94
132
  * # Syntax
95
133
  *
96
- * Derived from the [vers specification](https://www.packageurl.org/docs/vers/how-to-parse) and
134
+ * Derived from the [VERS specification](https://www.packageurl.org/docs/vers/how-to-parse),
97
135
  * its comments in
98
136
  * [CSAF 2.0](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#31232-branches-type---name-under-product-version-range)
99
137
  * and
100
138
  * [CSAF 2.1](https://docs.oasis-open.org/csaf/csaf/v2.1/csaf-v2.1.html#branches-type---name-under-product-version-range).
101
139
  *
102
- * There currently is no "official" grammar for vers-like specifier / the `<constraints>` part of
103
- * vers. This is a best-effort attempt used for this library.
104
- *
105
- * **Note:** This grammar may need to be updated once vers has been ratified through ECMA / following changes
106
- * to / clarifications of CSAF 2.0 or CSAF 2.1.
107
- *
108
- * ```text
109
- * vls = constraint *( "|" constraint )
110
- * constraint = comparator version-string / version-string
111
- * comparator = "!=" / "<=" / ">=" / "<" / ">"
112
- * version-string = 1*( ALPHA / DIGIT / "-" / "." / "_" / "+" / "~" )
113
- * ```
114
- *
115
- * For validation, this leads to two sets of characters allowed in the context of the grammar.
116
- *
117
- * For `constraints`: `ALPHA / DIGIT / "-" / "." / "_" / "+" / "~" / "=" / "!" / "<" / ">" / "|"`
118
- *
119
- * For `version-string`: `ALPHA / DIGIT / "-" / "." / "_" / "+" / "~"`
140
+ * There currently is no "official" grammar for VERS-like specifier / the `<constraints>` part of
141
+ * VERS. This is a best-effort attempt used for this library.
120
142
  *
121
143
  * # Examples
122
144
  *
@@ -135,6 +157,11 @@ export class Vls {
135
157
  private constructor();
136
158
  free(): void;
137
159
  [Symbol.dispose](): void;
160
+ /**
161
+ * Return the [`Containment`] of the given `version` in this specifier, exposed as the
162
+ * instance method `vls.contains(version)` in JS.
163
+ */
164
+ contains(version: string): Containment;
138
165
  /**
139
166
  * Return `true` if this specifier pins exactly one version, exposed as the
140
167
  * instance method `vls.isSingleVersion()` in JS.
@@ -144,7 +171,7 @@ export class Vls {
144
171
  * Parse a `vls` as a [`Vls`] string, exposed as the static `Vls.parse(vls)` in JS.
145
172
  *
146
173
  * # Errors
147
- * Throws a JS `Error` if `vls` is not a valid vers-like specifier.
174
+ * Throws a JS `Error` if `vls` is not a valid VERS-like specifier.
148
175
  */
149
176
  static parse(vls: string): Vls;
150
177
  }
@@ -158,14 +185,15 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
158
185
 
159
186
  export interface InitOutput {
160
187
  readonly memory: WebAssembly.Memory;
161
- readonly __wbg_constraint_free: (a: number, b: number) => void;
188
+ readonly init: () => void;
162
189
  readonly __wbg_vls_free: (a: number, b: number) => void;
190
+ readonly vls_contains: (a: number, b: number, c: number) => number;
191
+ readonly vls_isSingleVersion: (a: number) => number;
192
+ readonly vls_parse: (a: number, b: number) => [number, number, number];
193
+ readonly __wbg_constraint_free: (a: number, b: number) => void;
163
194
  readonly constraint_comparator: (a: number) => number;
164
195
  readonly constraint_version: (a: number) => [number, number];
165
196
  readonly constraint_wasm_new: (a: number, b: number, c: number) => [number, number, number];
166
- readonly vls_isSingleVersion: (a: number) => number;
167
- readonly vls_parse: (a: number, b: number) => [number, number, number];
168
- readonly init: () => void;
169
197
  readonly __wbindgen_free: (a: number, b: number, c: number) => void;
170
198
  readonly __wbindgen_malloc: (a: number, b: number) => number;
171
199
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
@@ -98,9 +98,48 @@ export class Constraint {
98
98
  if (Symbol.dispose) Constraint.prototype[Symbol.dispose] = Constraint.prototype.free;
99
99
 
100
100
  /**
101
- * A **Vers-like Specifier** (VLS).
101
+ * The result of a containment check performed by [`Vls::contains`].
102
102
  *
103
- * VLS is the `<constraints>` part of a [vers](https://github.com/package-url/vers-spec)
103
+ * Because the VERS type of a [`Vls`] is unspecified, containment can usually only be
104
+ * resolved when the queried version exactly matches a constraint's version:
105
+ *
106
+ * * [`Comparator::Equal`], [`Comparator::GreaterThanOrEqual`], [`Comparator::LessThanOrEqual`]:
107
+ * an exact match means the version is contained (`x = x`, `x >= x`, `x <= x` all hold) →
108
+ * [`Containment::Contained`].
109
+ * * [`Comparator::NotEqual`], [`Comparator::LessThan`], [`Comparator::GreaterThan`]:
110
+ * an exact match means the version is explicitly not contained (`x != x`, `x < x`, `x > x`
111
+ * are always false) → [`Containment::NotContained`].
112
+ * * No constraint's version matches exactly: containment cannot be resolved, as the VERS
113
+ * type is unknown / unspecified → [`Containment::Undetermined`].
114
+ *
115
+ * The one exception is a [`Vls`] that pins a single version (see [`Vls::is_single_version`]):
116
+ * since it has exactly one [`Comparator::Equal`] constraint, containment reduces to a plain
117
+ * string comparison and is always decidable, regardless of VERS type. In that case,
118
+ * *any* queried version resolves to either [`Containment::Contained`] or
119
+ * [`Containment::NotContained`], never [`Containment::Undetermined`].
120
+ * @enum {0 | 1 | 2}
121
+ */
122
+ export const Containment = Object.freeze({
123
+ /**
124
+ * The version is contained in the specifier.
125
+ */
126
+ Contained: 0, "0": "Contained",
127
+ /**
128
+ * The version is explicitly not contained in the specifier.
129
+ */
130
+ NotContained: 1, "1": "NotContained",
131
+ /**
132
+ * Containment could not be determined: the version does not exactly match any
133
+ * constraint, and the (unspecified) VERS type does not allow any further
134
+ * comparison.
135
+ */
136
+ Undetermined: 2, "2": "Undetermined",
137
+ });
138
+
139
+ /**
140
+ * A **VERS-like specifier** (vls).
141
+ *
142
+ * vls is the `<constraints>` part of a [VERS](https://github.com/package-url/vers-spec)
104
143
  * URL *without* the `vers:<type>/` prefix.
105
144
  *
106
145
  * It is an ordered, `|`-separated list of [`Constraint`] values.
@@ -112,30 +151,14 @@ if (Symbol.dispose) Constraint.prototype[Symbol.dispose] = Constraint.prototype.
112
151
  *
113
152
  * # Syntax
114
153
  *
115
- * Derived from the [vers specification](https://www.packageurl.org/docs/vers/how-to-parse) and
154
+ * Derived from the [VERS specification](https://www.packageurl.org/docs/vers/how-to-parse),
116
155
  * its comments in
117
156
  * [CSAF 2.0](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#31232-branches-type---name-under-product-version-range)
118
157
  * and
119
158
  * [CSAF 2.1](https://docs.oasis-open.org/csaf/csaf/v2.1/csaf-v2.1.html#branches-type---name-under-product-version-range).
120
159
  *
121
- * There currently is no "official" grammar for vers-like specifier / the `<constraints>` part of
122
- * vers. This is a best-effort attempt used for this library.
123
- *
124
- * **Note:** This grammar may need to be updated once vers has been ratified through ECMA / following changes
125
- * to / clarifications of CSAF 2.0 or CSAF 2.1.
126
- *
127
- * ```text
128
- * vls = constraint *( "|" constraint )
129
- * constraint = comparator version-string / version-string
130
- * comparator = "!=" / "<=" / ">=" / "<" / ">"
131
- * version-string = 1*( ALPHA / DIGIT / "-" / "." / "_" / "+" / "~" )
132
- * ```
133
- *
134
- * For validation, this leads to two sets of characters allowed in the context of the grammar.
135
- *
136
- * For `constraints`: `ALPHA / DIGIT / "-" / "." / "_" / "+" / "~" / "=" / "!" / "<" / ">" / "|"`
137
- *
138
- * For `version-string`: `ALPHA / DIGIT / "-" / "." / "_" / "+" / "~"`
160
+ * There currently is no "official" grammar for VERS-like specifier / the `<constraints>` part of
161
+ * VERS. This is a best-effort attempt used for this library.
139
162
  *
140
163
  * # Examples
141
164
  *
@@ -168,6 +191,18 @@ export class Vls {
168
191
  const ptr = this.__destroy_into_raw();
169
192
  wasm.__wbg_vls_free(ptr, 0);
170
193
  }
194
+ /**
195
+ * Return the [`Containment`] of the given `version` in this specifier, exposed as the
196
+ * instance method `vls.contains(version)` in JS.
197
+ * @param {string} version
198
+ * @returns {Containment}
199
+ */
200
+ contains(version) {
201
+ const ptr0 = passStringToWasm0(version, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
202
+ const len0 = WASM_VECTOR_LEN;
203
+ const ret = wasm.vls_contains(this.__wbg_ptr, ptr0, len0);
204
+ return ret;
205
+ }
171
206
  /**
172
207
  * Return `true` if this specifier pins exactly one version, exposed as the
173
208
  * instance method `vls.isSingleVersion()` in JS.
@@ -181,7 +216,7 @@ export class Vls {
181
216
  * Parse a `vls` as a [`Vls`] string, exposed as the static `Vls.parse(vls)` in JS.
182
217
  *
183
218
  * # Errors
184
- * Throws a JS `Error` if `vls` is not a valid vers-like specifier.
219
+ * Throws a JS `Error` if `vls` is not a valid VERS-like specifier.
185
220
  * @param {string} vls
186
221
  * @returns {Vls}
187
222
  */
Binary file