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

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
 
@@ -21,13 +21,13 @@ Add `vers-like-specifier` to your `Cargo.toml`. The package is published on http
21
21
 
22
22
  ```toml
23
23
  [dependencies]
24
- vers-like-specifier = "0.1"
24
+ vers-like-specifier = "0.2"
25
25
  ```
26
26
 
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);
@@ -35,32 +35,45 @@ assert_eq!(vls.to_string(), ">=1.0.0|<2.0.0");
35
35
 
36
36
 
37
37
  let constraints = vls.constraints();
38
- assert_eq!(constraints[0].comparator(), &Comparator::GreaterThanOrEqual);
38
+ assert_eq!(constraints[0].comparator(), Comparator::GreaterThanOrEqual);
39
39
  assert_eq!(constraints[0].version().to_string(), "1.0.0");
40
- assert_eq!(constraints[1].comparator(), &Comparator::LessThan);
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 containing only exact-match comparators (equal, not equal) is always decidable, since
50
+ // containment then reduces to a plain string comparison if there is a constraint with that version. If there isn't a
51
+ // constraint with the version, it is not contained by default.
52
+ let exact_only: Vls = "1.0.0|!=2.0.0".parse().unwrap();
53
+ assert_eq!(exact_only.contains("1.0.0"), Containment::Contained);
54
+ assert_eq!(exact_only.contains("2.0.0"), Containment::NotContained);
55
+ assert_eq!(exact_only.contains("3.0.0"), Containment::NotContained);
42
56
  ```
43
57
 
44
58
  ### JavaScript / WASM Usage
45
59
 
46
60
  ```js
47
- import init, { Vls, Constraint, Comparator } from "@csaf-rs/vers-like-specifier";
61
+ import init, { Vls, Constraint, Comparator, Containment } from "@csaf-rs/vers-like-specifier";
48
62
 
49
63
  await init();
50
64
 
51
65
  const vls = Vls.parse(">=1.0.0|<2.0.0");
52
- console.log(vls.isSingleVersion()); // false
53
-
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
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@csaf-rs/vers-like-specifier",
3
3
  "type": "module",
4
- "description": "vls (vers-like specifier) parser",
5
- "version": "0.1.2",
4
+ "description": "vls (VERS-like specifier) parser",
5
+ "version": "0.2.0",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -9,14 +9,14 @@
9
9
  export type VersionString = string;
10
10
 
11
11
  /**
12
- * Errors specific to a single constraint within a VLS string.
12
+ * Errors specific to a single constraint within a vls string.
13
13
  */
14
14
  export type ConstraintError = "EmptyConstraint" | "EmptyConstraintVersion" | { InvalidConstraintVersionCharacters: string[] };
15
15
 
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" | { SingleVersionNotAllowed: string } | { InvalidCharacters: string[] } | { InvalidConstraints: ConstraintError[] } | { DuplicateConstraintVersions: string[] } | { Serialization: string };
20
20
 
21
21
 
22
22
  /**
@@ -61,7 +61,7 @@ export class Constraint {
61
61
  [Symbol.dispose](): void;
62
62
  /**
63
63
  * Construct a new [`Constraint`] from a [`Comparator`] and a version string, validating
64
- * the version string against the VLS grammar. Exposed as `new Constraint(comparator, version)`
64
+ * the version string against the vls grammar. Exposed as `new Constraint(comparator, version)`
65
65
  * in JS.
66
66
  *
67
67
  * # Errors
@@ -79,9 +79,48 @@ 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 uses only exact-match comparators (i.e.
97
+ * [`Comparator::Equal`] and/or [`Comparator::NotEqual`]).
98
+ * Here, containment is reduced to a plain string comparison and is always decidable,
99
+ * regardless of VERS type. In that case, *any* queried version resolves to either [`Containment::Contained`] or
100
+ * [`Containment::NotContained`] depending on the exact-match comparator if there is a constraint with
101
+ * the queried version, and always to [`Containment::NotContained`] if there is no constraint with that version.
102
+ */
103
+ export enum Containment {
104
+ /**
105
+ * The version is contained in the specifier.
106
+ */
107
+ Contained = 0,
108
+ /**
109
+ * The version is explicitly not contained in the specifier.
110
+ */
111
+ NotContained = 1,
112
+ /**
113
+ * Containment could not be determined: the version does not exactly match any
114
+ * constraint, and the (unspecified) VERS type does not allow any further
115
+ * comparison.
116
+ */
117
+ Undetermined = 2,
118
+ }
119
+
120
+ /**
121
+ * A **VERS-like specifier** (vls).
83
122
  *
84
- * VLS is the `<constraints>` part of a [vers](https://github.com/package-url/vers-spec)
123
+ * vls is the `<constraints>` part of a [VERS](https://github.com/package-url/vers-spec)
85
124
  * URL *without* the `vers:<type>/` prefix.
86
125
  *
87
126
  * It is an ordered, `|`-separated list of [`Constraint`] values.
@@ -93,30 +132,14 @@ export class Constraint {
93
132
  *
94
133
  * # Syntax
95
134
  *
96
- * Derived from the [vers specification](https://www.packageurl.org/docs/vers/how-to-parse) and
135
+ * Derived from the [VERS specification](https://www.packageurl.org/docs/vers/how-to-parse),
97
136
  * its comments in
98
137
  * [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
138
  * and
100
139
  * [CSAF 2.1](https://docs.oasis-open.org/csaf/csaf/v2.1/csaf-v2.1.html#branches-type---name-under-product-version-range).
101
140
  *
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 / "-" / "." / "_" / "+" / "~"`
141
+ * There currently is no "official" grammar for VERS-like specifier / the `<constraints>` part of
142
+ * VERS. This is a best-effort attempt used for this library.
120
143
  *
121
144
  * # Examples
122
145
  *
@@ -136,15 +159,15 @@ export class Vls {
136
159
  free(): void;
137
160
  [Symbol.dispose](): void;
138
161
  /**
139
- * Return `true` if this specifier pins exactly one version, exposed as the
140
- * instance method `vls.isSingleVersion()` in JS.
162
+ * Return the [`Containment`] of the given `version` in this specifier, exposed as the
163
+ * instance method `vls.contains(version)` in JS.
141
164
  */
142
- isSingleVersion(): boolean;
165
+ contains(version: string): Containment;
143
166
  /**
144
167
  * Parse a `vls` as a [`Vls`] string, exposed as the static `Vls.parse(vls)` in JS.
145
168
  *
146
169
  * # Errors
147
- * Throws a JS `Error` if `vls` is not a valid vers-like specifier.
170
+ * Throws a JS `Error` if `vls` is not a valid VERS-like specifier.
148
171
  */
149
172
  static parse(vls: string): Vls;
150
173
  }
@@ -158,14 +181,14 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
158
181
 
159
182
  export interface InitOutput {
160
183
  readonly memory: WebAssembly.Memory;
161
- readonly __wbg_constraint_free: (a: number, b: number) => void;
184
+ readonly init: () => void;
162
185
  readonly __wbg_vls_free: (a: number, b: number) => void;
186
+ readonly vls_contains: (a: number, b: number, c: number) => number;
187
+ readonly vls_parse: (a: number, b: number) => [number, number, number];
188
+ readonly __wbg_constraint_free: (a: number, b: number) => void;
163
189
  readonly constraint_comparator: (a: number) => number;
164
190
  readonly constraint_version: (a: number) => [number, number];
165
191
  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
192
  readonly __wbindgen_free: (a: number, b: number, c: number) => void;
170
193
  readonly __wbindgen_malloc: (a: number, b: number) => number;
171
194
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
@@ -75,7 +75,7 @@ export class Constraint {
75
75
  }
76
76
  /**
77
77
  * Construct a new [`Constraint`] from a [`Comparator`] and a version string, validating
78
- * the version string against the VLS grammar. Exposed as `new Constraint(comparator, version)`
78
+ * the version string against the vls grammar. Exposed as `new Constraint(comparator, version)`
79
79
  * in JS.
80
80
  *
81
81
  * # Errors
@@ -98,9 +98,49 @@ 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 uses only exact-match comparators (i.e.
116
+ * [`Comparator::Equal`] and/or [`Comparator::NotEqual`]).
117
+ * Here, containment is reduced to a plain string comparison and is always decidable,
118
+ * regardless of VERS type. In that case, *any* queried version resolves to either [`Containment::Contained`] or
119
+ * [`Containment::NotContained`] depending on the exact-match comparator if there is a constraint with
120
+ * the queried version, and always to [`Containment::NotContained`] if there is no constraint with that version.
121
+ * @enum {0 | 1 | 2}
122
+ */
123
+ export const Containment = Object.freeze({
124
+ /**
125
+ * The version is contained in the specifier.
126
+ */
127
+ Contained: 0, "0": "Contained",
128
+ /**
129
+ * The version is explicitly not contained in the specifier.
130
+ */
131
+ NotContained: 1, "1": "NotContained",
132
+ /**
133
+ * Containment could not be determined: the version does not exactly match any
134
+ * constraint, and the (unspecified) VERS type does not allow any further
135
+ * comparison.
136
+ */
137
+ Undetermined: 2, "2": "Undetermined",
138
+ });
139
+
140
+ /**
141
+ * A **VERS-like specifier** (vls).
142
+ *
143
+ * vls is the `<constraints>` part of a [VERS](https://github.com/package-url/vers-spec)
104
144
  * URL *without* the `vers:<type>/` prefix.
105
145
  *
106
146
  * It is an ordered, `|`-separated list of [`Constraint`] values.
@@ -112,30 +152,14 @@ if (Symbol.dispose) Constraint.prototype[Symbol.dispose] = Constraint.prototype.
112
152
  *
113
153
  * # Syntax
114
154
  *
115
- * Derived from the [vers specification](https://www.packageurl.org/docs/vers/how-to-parse) and
155
+ * Derived from the [VERS specification](https://www.packageurl.org/docs/vers/how-to-parse),
116
156
  * its comments in
117
157
  * [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
158
  * and
119
159
  * [CSAF 2.1](https://docs.oasis-open.org/csaf/csaf/v2.1/csaf-v2.1.html#branches-type---name-under-product-version-range).
120
160
  *
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 / "-" / "." / "_" / "+" / "~"`
161
+ * There currently is no "official" grammar for VERS-like specifier / the `<constraints>` part of
162
+ * VERS. This is a best-effort attempt used for this library.
139
163
  *
140
164
  * # Examples
141
165
  *
@@ -169,19 +193,22 @@ export class Vls {
169
193
  wasm.__wbg_vls_free(ptr, 0);
170
194
  }
171
195
  /**
172
- * Return `true` if this specifier pins exactly one version, exposed as the
173
- * instance method `vls.isSingleVersion()` in JS.
174
- * @returns {boolean}
196
+ * Return the [`Containment`] of the given `version` in this specifier, exposed as the
197
+ * instance method `vls.contains(version)` in JS.
198
+ * @param {string} version
199
+ * @returns {Containment}
175
200
  */
176
- isSingleVersion() {
177
- const ret = wasm.vls_isSingleVersion(this.__wbg_ptr);
178
- return ret !== 0;
201
+ contains(version) {
202
+ const ptr0 = passStringToWasm0(version, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
203
+ const len0 = WASM_VECTOR_LEN;
204
+ const ret = wasm.vls_contains(this.__wbg_ptr, ptr0, len0);
205
+ return ret;
179
206
  }
180
207
  /**
181
208
  * Parse a `vls` as a [`Vls`] string, exposed as the static `Vls.parse(vls)` in JS.
182
209
  *
183
210
  * # Errors
184
- * Throws a JS `Error` if `vls` is not a valid vers-like specifier.
211
+ * Throws a JS `Error` if `vls` is not a valid VERS-like specifier.
185
212
  * @param {string} vls
186
213
  * @returns {Vls}
187
214
  */
Binary file