@cyclonedx/cdxgen 12.1.5 → 12.2.1

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.
Files changed (193) hide show
  1. package/README.md +51 -40
  2. package/bin/cdxgen.js +194 -97
  3. package/bin/evinse.js +4 -4
  4. package/bin/repl.js +1 -1
  5. package/bin/sign.js +102 -0
  6. package/bin/validate.js +233 -0
  7. package/bin/verify.js +69 -28
  8. package/data/queries.json +1 -1
  9. package/data/rules/ci-permissions.yaml +186 -0
  10. package/data/rules/dependency-sources.yaml +123 -0
  11. package/data/rules/package-integrity.yaml +135 -0
  12. package/data/rules/vscode-extensions.yaml +228 -0
  13. package/lib/cli/index.js +449 -429
  14. package/lib/cli/index.poku.js +117 -0
  15. package/lib/evinser/db.js +137 -0
  16. package/lib/{helpers → evinser}/db.poku.js +2 -6
  17. package/lib/evinser/evinser.js +2 -14
  18. package/lib/helpers/analyzer.js +606 -3
  19. package/lib/helpers/analyzer.poku.js +230 -0
  20. package/lib/helpers/bomSigner.js +312 -0
  21. package/lib/helpers/bomSigner.poku.js +156 -0
  22. package/lib/helpers/ciParsers/azurePipelines.js +295 -0
  23. package/lib/helpers/ciParsers/azurePipelines.poku.js +253 -0
  24. package/lib/helpers/ciParsers/circleCi.js +286 -0
  25. package/lib/helpers/ciParsers/circleCi.poku.js +230 -0
  26. package/lib/helpers/ciParsers/common.js +24 -0
  27. package/lib/helpers/ciParsers/githubActions.js +636 -0
  28. package/lib/helpers/ciParsers/githubActions.poku.js +802 -0
  29. package/lib/helpers/ciParsers/gitlabCi.js +213 -0
  30. package/lib/helpers/ciParsers/gitlabCi.poku.js +247 -0
  31. package/lib/helpers/ciParsers/jenkins.js +181 -0
  32. package/lib/helpers/ciParsers/jenkins.poku.js +197 -0
  33. package/lib/helpers/depsUtils.js +219 -0
  34. package/lib/helpers/depsUtils.poku.js +207 -0
  35. package/lib/helpers/display.js +426 -5
  36. package/lib/helpers/envcontext.js +18 -3
  37. package/lib/helpers/formulationParsers.js +351 -0
  38. package/lib/helpers/logger.js +14 -0
  39. package/lib/helpers/protobom.js +9 -9
  40. package/lib/helpers/pythonutils.js +9 -0
  41. package/lib/helpers/remote/dependency-track.js +84 -0
  42. package/lib/helpers/remote/dependency-track.poku.js +119 -0
  43. package/lib/helpers/table.js +384 -0
  44. package/lib/helpers/table.poku.js +186 -0
  45. package/lib/helpers/utils.js +865 -416
  46. package/lib/helpers/utils.poku.js +172 -265
  47. package/lib/helpers/versutils.js +202 -0
  48. package/lib/helpers/versutils.poku.js +315 -0
  49. package/lib/helpers/vsixutils.js +1061 -0
  50. package/lib/helpers/vsixutils.poku.js +2247 -0
  51. package/lib/managers/binary.js +19 -19
  52. package/lib/managers/docker.js +108 -1
  53. package/lib/managers/oci.js +10 -0
  54. package/lib/managers/piptree.js +3 -9
  55. package/lib/parsers/npmrc.js +17 -13
  56. package/lib/parsers/npmrc.poku.js +41 -5
  57. package/lib/server/openapi.yaml +34 -1
  58. package/lib/server/server.js +50 -13
  59. package/lib/server/server.poku.js +332 -144
  60. package/lib/stages/postgen/annotator.js +1 -1
  61. package/lib/stages/postgen/auditBom.js +196 -0
  62. package/lib/stages/postgen/auditBom.poku.js +378 -0
  63. package/lib/stages/postgen/postgen.js +54 -1
  64. package/lib/stages/postgen/postgen.poku.js +90 -1
  65. package/lib/stages/postgen/ruleEngine.js +369 -0
  66. package/lib/stages/pregen/envAudit.js +299 -0
  67. package/lib/stages/pregen/envAudit.poku.js +572 -0
  68. package/lib/stages/pregen/pregen.js +12 -8
  69. package/lib/{helpers/validator.js → validator/bomValidator.js} +107 -47
  70. package/lib/validator/complianceEngine.js +241 -0
  71. package/lib/validator/complianceEngine.poku.js +168 -0
  72. package/lib/validator/complianceRules.js +1610 -0
  73. package/lib/validator/complianceRules.poku.js +328 -0
  74. package/lib/validator/index.js +222 -0
  75. package/lib/validator/index.poku.js +144 -0
  76. package/lib/validator/reporters/annotations.js +121 -0
  77. package/lib/validator/reporters/console.js +149 -0
  78. package/lib/validator/reporters/index.js +41 -0
  79. package/lib/validator/reporters/json.js +37 -0
  80. package/lib/validator/reporters/sarif.js +184 -0
  81. package/lib/validator/reporters.poku.js +150 -0
  82. package/package.json +8 -9
  83. package/types/bin/sign.d.ts +3 -0
  84. package/types/bin/sign.d.ts.map +1 -0
  85. package/types/bin/validate.d.ts +3 -0
  86. package/types/bin/validate.d.ts.map +1 -0
  87. package/types/helpers/utils.d.ts +0 -1
  88. package/types/lib/cli/index.d.ts +49 -52
  89. package/types/lib/cli/index.d.ts.map +1 -1
  90. package/types/lib/evinser/db.d.ts +34 -0
  91. package/types/lib/evinser/db.d.ts.map +1 -0
  92. package/types/lib/evinser/evinser.d.ts +63 -16
  93. package/types/lib/evinser/evinser.d.ts.map +1 -1
  94. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  95. package/types/lib/helpers/bomSigner.d.ts +27 -0
  96. package/types/lib/helpers/bomSigner.d.ts.map +1 -0
  97. package/types/lib/helpers/ciParsers/azurePipelines.d.ts +17 -0
  98. package/types/lib/helpers/ciParsers/azurePipelines.d.ts.map +1 -0
  99. package/types/lib/helpers/ciParsers/circleCi.d.ts +17 -0
  100. package/types/lib/helpers/ciParsers/circleCi.d.ts.map +1 -0
  101. package/types/lib/helpers/ciParsers/common.d.ts +11 -0
  102. package/types/lib/helpers/ciParsers/common.d.ts.map +1 -0
  103. package/types/lib/helpers/ciParsers/githubActions.d.ts +34 -0
  104. package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -0
  105. package/types/lib/helpers/ciParsers/gitlabCi.d.ts +17 -0
  106. package/types/lib/helpers/ciParsers/gitlabCi.d.ts.map +1 -0
  107. package/types/lib/helpers/ciParsers/jenkins.d.ts +17 -0
  108. package/types/lib/helpers/ciParsers/jenkins.d.ts.map +1 -0
  109. package/types/lib/helpers/depsUtils.d.ts +21 -0
  110. package/types/lib/helpers/depsUtils.d.ts.map +1 -0
  111. package/types/lib/helpers/display.d.ts +111 -11
  112. package/types/lib/helpers/display.d.ts.map +1 -1
  113. package/types/lib/helpers/envcontext.d.ts +19 -7
  114. package/types/lib/helpers/envcontext.d.ts.map +1 -1
  115. package/types/lib/helpers/formulationParsers.d.ts +50 -0
  116. package/types/lib/helpers/formulationParsers.d.ts.map +1 -0
  117. package/types/lib/helpers/logger.d.ts +15 -1
  118. package/types/lib/helpers/logger.d.ts.map +1 -1
  119. package/types/lib/helpers/protobom.d.ts +2 -2
  120. package/types/lib/helpers/pythonutils.d.ts +10 -1
  121. package/types/lib/helpers/pythonutils.d.ts.map +1 -1
  122. package/types/lib/helpers/remote/dependency-track.d.ts +16 -0
  123. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
  124. package/types/lib/helpers/table.d.ts +6 -0
  125. package/types/lib/helpers/table.d.ts.map +1 -0
  126. package/types/lib/helpers/utils.d.ts +533 -128
  127. package/types/lib/helpers/utils.d.ts.map +1 -1
  128. package/types/lib/helpers/versutils.d.ts +8 -0
  129. package/types/lib/helpers/versutils.d.ts.map +1 -0
  130. package/types/lib/helpers/vsixutils.d.ts +130 -0
  131. package/types/lib/helpers/vsixutils.d.ts.map +1 -0
  132. package/types/lib/managers/docker.d.ts +12 -31
  133. package/types/lib/managers/docker.d.ts.map +1 -1
  134. package/types/lib/managers/oci.d.ts +11 -1
  135. package/types/lib/managers/oci.d.ts.map +1 -1
  136. package/types/lib/managers/piptree.d.ts.map +1 -1
  137. package/types/lib/parsers/npmrc.d.ts +4 -1
  138. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  139. package/types/lib/server/server.d.ts +22 -2
  140. package/types/lib/server/server.d.ts.map +1 -1
  141. package/types/lib/stages/postgen/auditBom.d.ts +20 -0
  142. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
  143. package/types/lib/stages/postgen/postgen.d.ts +8 -1
  144. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  145. package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
  146. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
  147. package/types/lib/stages/pregen/envAudit.d.ts +8 -0
  148. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
  149. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  150. package/types/lib/{helpers/validator.d.ts → validator/bomValidator.d.ts} +1 -1
  151. package/types/lib/validator/bomValidator.d.ts.map +1 -0
  152. package/types/lib/validator/complianceEngine.d.ts +66 -0
  153. package/types/lib/validator/complianceEngine.d.ts.map +1 -0
  154. package/types/lib/validator/complianceRules.d.ts +70 -0
  155. package/types/lib/validator/complianceRules.d.ts.map +1 -0
  156. package/types/lib/validator/index.d.ts +70 -0
  157. package/types/lib/validator/index.d.ts.map +1 -0
  158. package/types/lib/validator/reporters/annotations.d.ts +31 -0
  159. package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
  160. package/types/lib/validator/reporters/console.d.ts +30 -0
  161. package/types/lib/validator/reporters/console.d.ts.map +1 -0
  162. package/types/lib/validator/reporters/index.d.ts +21 -0
  163. package/types/lib/validator/reporters/index.d.ts.map +1 -0
  164. package/types/lib/validator/reporters/json.d.ts +11 -0
  165. package/types/lib/validator/reporters/json.d.ts.map +1 -0
  166. package/types/lib/validator/reporters/sarif.d.ts +16 -0
  167. package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
  168. package/lib/helpers/db.js +0 -162
  169. package/lib/stages/pregen/env-audit.js +0 -34
  170. package/lib/stages/pregen/env-audit.poku.js +0 -290
  171. package/types/helpers/db.d.ts +0 -35
  172. package/types/helpers/db.d.ts.map +0 -1
  173. package/types/lib/helpers/db.d.ts +0 -35
  174. package/types/lib/helpers/db.d.ts.map +0 -1
  175. package/types/lib/helpers/validator.d.ts.map +0 -1
  176. package/types/lib/stages/pregen/env-audit.d.ts +0 -2
  177. package/types/lib/stages/pregen/env-audit.d.ts.map +0 -1
  178. package/types/managers/binary.d.ts +0 -37
  179. package/types/managers/binary.d.ts.map +0 -1
  180. package/types/managers/docker.d.ts +0 -56
  181. package/types/managers/docker.d.ts.map +0 -1
  182. package/types/managers/oci.d.ts +0 -2
  183. package/types/managers/oci.d.ts.map +0 -1
  184. package/types/managers/piptree.d.ts +0 -2
  185. package/types/managers/piptree.d.ts.map +0 -1
  186. package/types/server/server.d.ts +0 -34
  187. package/types/server/server.d.ts.map +0 -1
  188. package/types/stages/postgen/annotator.d.ts +0 -27
  189. package/types/stages/postgen/annotator.d.ts.map +0 -1
  190. package/types/stages/postgen/postgen.d.ts +0 -51
  191. package/types/stages/postgen/postgen.d.ts.map +0 -1
  192. package/types/stages/pregen/pregen.d.ts +0 -59
  193. package/types/stages/pregen/pregen.d.ts.map +0 -1
@@ -0,0 +1,202 @@
1
+ function parseVersion(v) {
2
+ const m = v.match(/^([><=^~]+)?(.*)$/);
3
+ const ver = m ? m[2] : v;
4
+ if (ver === "*")
5
+ return { major: 0, minor: 0, patch: 0, pre: "", op: "", isStar: true };
6
+ const parts = ver.split("-");
7
+ const main = parts[0].split(".");
8
+ return {
9
+ op: m ? m[1] || "" : "",
10
+ major: Number.parseInt(main[0] || "0", 10),
11
+ minor: Number.parseInt(main[1] || "0", 10),
12
+ patch: Number.parseInt(main[2] || "0", 10),
13
+ pre: parts.slice(1).join("-"),
14
+ };
15
+ }
16
+
17
+ /**
18
+ * Converts a package.json npm version specifier to a VERS format range.
19
+ *
20
+ * @param {string} versionString - The native npm semver string.
21
+ * @returns {string} The formatted vers:npm range string.
22
+ */
23
+ export function toVersRange(versionString) {
24
+ if (!versionString || typeof versionString !== "string") {
25
+ return "";
26
+ }
27
+ let str = versionString.trim();
28
+ if (!str) {
29
+ return "";
30
+ }
31
+ if (str === "latest" || str.startsWith("workspace:")) {
32
+ return "";
33
+ }
34
+ if (str === "*") {
35
+ return "vers:npm/*";
36
+ }
37
+ // Replace hyphen ranges: A - B -> >=A <=B
38
+ str = str.replace(/([\w.-]+)\s+-\s+([\w.-]+)/g, ">= $1 <= $2");
39
+
40
+ // Split logical ORs
41
+ const ors = str.split("||").map((s) => s.trim());
42
+ const allBounds = [];
43
+
44
+ for (let part of ors) {
45
+ // Normalize spaces after operators to attach them to the version
46
+ part = part.replace(/([><=^~]+)\s+/g, "$1");
47
+ part = part.replace(/\s+/g, " ");
48
+
49
+ const tokens = part.split(" ").filter(Boolean);
50
+
51
+ for (let token of tokens) {
52
+ // Strip the 'v' prefix if present (e.g. >=v1.2.3 -> >=1.2.3)
53
+ token = token.replace(/^([><=^~]+)?v/i, (_match, op) => op || "");
54
+
55
+ if (token === "*") {
56
+ allBounds.push("*");
57
+ continue;
58
+ }
59
+
60
+ const match = token.match(/^([><=^~]+)?(.*)$/);
61
+ const op = match[1] || "";
62
+ let ver = match[2];
63
+
64
+ if (ver === "*") {
65
+ allBounds.push("*");
66
+ continue;
67
+ }
68
+
69
+ // Pad versions (e.g., '1' -> '1.0.0', '1.1' -> '1.1.0')
70
+ if (/^\d+$/.test(ver)) {
71
+ ver += ".0.0";
72
+ } else if (/^\d+\.\d+$/.test(ver)) {
73
+ ver += ".0";
74
+ }
75
+
76
+ // Handle .x or .* ranges
77
+ if (ver.endsWith(".x") || ver.endsWith(".*")) {
78
+ const parts = ver.split(".");
79
+ if (parts[1] === "x" || parts[1] === "*") {
80
+ const M = Number.parseInt(parts[0], 10);
81
+ allBounds.push(`>=${M}.0.0`, `<${M + 1}.0.0`);
82
+ } else if (parts[2] === "x" || parts[2] === "*") {
83
+ const M = parts[0];
84
+ const m_minor = Number.parseInt(parts[1], 10);
85
+ allBounds.push(`>=${M}.${m_minor}.0`, `<${M}.${m_minor + 1}.0`);
86
+ }
87
+ continue;
88
+ }
89
+
90
+ // Caret (^) expansion
91
+ if (op === "^") {
92
+ const m = ver.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/);
93
+ if (!m) {
94
+ allBounds.push(`${op}${ver}`);
95
+ continue;
96
+ }
97
+ const M = Number.parseInt(m[1], 10);
98
+ const m_minor = Number.parseInt(m[2], 10);
99
+ const p = Number.parseInt(m[3], 10);
100
+ let upper;
101
+ if (M > 0) {
102
+ upper = `${M + 1}.0.0`;
103
+ } else if (m_minor > 0) {
104
+ upper = `0.${m_minor + 1}.0`;
105
+ } else {
106
+ upper = `0.0.${p + 1}`;
107
+ }
108
+ allBounds.push(`>=${ver}`, `<${upper}`);
109
+ continue;
110
+ }
111
+
112
+ // Tilde (~) expansion
113
+ if (op === "~") {
114
+ const m = ver.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/);
115
+ if (!m) {
116
+ allBounds.push(`${op}${ver}`);
117
+ continue;
118
+ }
119
+ if (ver.includes("-pre")) {
120
+ const sv = parseVersion(ver);
121
+ const upper = `${sv.major}.${sv.minor}.0`;
122
+ const upper_1 = `${sv.major}.${sv.minor}.1`;
123
+ allBounds.push(`>=${ver}`, `<${upper}`, `>=${upper}`, `<${upper_1}`);
124
+ continue;
125
+ }
126
+ const M = Number.parseInt(m[1], 10);
127
+ const m_minor = Number.parseInt(m[2], 10);
128
+ const upper = `${M}.${m_minor + 1}.0`;
129
+ allBounds.push(`>=${ver}`, `<${upper}`);
130
+ continue;
131
+ }
132
+
133
+ if (op === "=") {
134
+ allBounds.push(ver);
135
+ continue;
136
+ }
137
+
138
+ // Exact fallback matches
139
+ if (op === "") {
140
+ allBounds.push(ver);
141
+ continue;
142
+ }
143
+
144
+ allBounds.push(op + ver);
145
+ }
146
+ }
147
+
148
+ // Sort all bounded intervals linearly mapped by semver precedence
149
+ allBounds.sort((aStr, bStr) => {
150
+ if (aStr === "*" && bStr === "*") return 0;
151
+ if (aStr === "*") return -1;
152
+ if (bStr === "*") return 1;
153
+
154
+ const a = parseVersion(aStr);
155
+ const b = parseVersion(bStr);
156
+
157
+ if (a.major !== b.major) return a.major - b.major;
158
+ if (a.minor !== b.minor) return a.minor - b.minor;
159
+ if (a.patch !== b.patch) return a.patch - b.patch;
160
+
161
+ if (a.pre && !b.pre) return -1;
162
+ if (!a.pre && b.pre) return 1;
163
+
164
+ if (a.pre && b.pre) {
165
+ if (a.pre !== b.pre) {
166
+ const aPre = a.pre.split(".");
167
+ const bPre = b.pre.split(".");
168
+ for (let i = 0; i < Math.max(aPre.length, bPre.length); i++) {
169
+ const ap = aPre[i];
170
+ const bp = bPre[i];
171
+
172
+ if (ap === undefined) return -1;
173
+ if (bp === undefined) return 1;
174
+
175
+ const apNum = /^\d+$/.test(ap);
176
+ const bpNum = /^\d+$/.test(bp);
177
+
178
+ if (apNum && bpNum) {
179
+ const diff = Number.parseInt(ap, 10) - Number.parseInt(bp, 10);
180
+ if (diff !== 0) return diff;
181
+ } else if (apNum && !bpNum) {
182
+ return -1;
183
+ } else if (!apNum && bpNum) {
184
+ return 1;
185
+ } else {
186
+ if (ap < bp) return -1;
187
+ if (ap > bp) return 1;
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ const opOrder = { "<": 1, "<=": 2, "": 3, ">=": 4, ">": 5 };
194
+ const aOp = opOrder[a.op] || 3;
195
+ const bOp = opOrder[b.op] || 3;
196
+ if (aOp !== bOp) return aOp - bOp;
197
+
198
+ return 0;
199
+ });
200
+
201
+ return `vers:npm/${allBounds.join("|")}`;
202
+ }
@@ -0,0 +1,315 @@
1
+ import { strict as assert } from "node:assert";
2
+
3
+ import { describe, it } from "poku";
4
+
5
+ import { toVersRange } from "./versutils.js";
6
+
7
+ describe("toVersRange", () => {
8
+ // === Basic Validation ===
9
+ describe("input validation", () => {
10
+ it("should return empty for null/undefined/empty", () => {
11
+ assert.strictEqual(toVersRange(null), "");
12
+ assert.strictEqual(toVersRange(undefined), "");
13
+ assert.strictEqual(toVersRange(""), "");
14
+ assert.strictEqual(toVersRange(" "), "");
15
+ });
16
+
17
+ it("should return empty for non-string input", () => {
18
+ assert.strictEqual(toVersRange(123), "");
19
+ assert.strictEqual(toVersRange({}), "");
20
+ assert.strictEqual(toVersRange([]), "");
21
+ });
22
+ });
23
+
24
+ // === Special Markers ===
25
+ describe("special markers", () => {
26
+ it("should handle wildcard '*'", () => {
27
+ assert.strictEqual(toVersRange("*"), "vers:npm/*");
28
+ });
29
+
30
+ it("should return empty for 'latest'", () => {
31
+ assert.strictEqual(toVersRange("latest"), "");
32
+ });
33
+
34
+ it("should return empty for workspace:* references", () => {
35
+ assert.strictEqual(toVersRange("workspace:*"), "");
36
+ assert.strictEqual(toVersRange("workspace:^1.0.0"), "");
37
+ assert.strictEqual(toVersRange("workspace:~"), "");
38
+ });
39
+ });
40
+
41
+ // === Simple Operators ===
42
+ describe("simple comparison operators", () => {
43
+ it("should handle >= operator", () => {
44
+ assert.strictEqual(toVersRange(">=4.1.0"), "vers:npm/>=4.1.0");
45
+ assert.strictEqual(toVersRange(">= 1.6.9"), "vers:npm/>=1.6.9");
46
+ assert.strictEqual(
47
+ toVersRange(">=v2.0.0-alpha8"),
48
+ "vers:npm/>=2.0.0-alpha8",
49
+ );
50
+ });
51
+
52
+ it("should handle <= operator", () => {
53
+ assert.strictEqual(toVersRange("<=4.0.4"), "vers:npm/<=4.0.4");
54
+ assert.strictEqual(toVersRange("<= 1.6.8"), "vers:npm/<=1.6.8");
55
+ assert.strictEqual(
56
+ toVersRange("<=v2.0.0-alpha7"),
57
+ "vers:npm/<=2.0.0-alpha7",
58
+ );
59
+ });
60
+
61
+ it("should handle < operator", () => {
62
+ assert.strictEqual(toVersRange("<0.0.0"), "vers:npm/<0.0.0");
63
+ assert.strictEqual(toVersRange("<2.11.2"), "vers:npm/<2.11.2");
64
+ assert.strictEqual(toVersRange("< 6.1.0"), "vers:npm/<6.1.0");
65
+ });
66
+
67
+ it("should handle > operator", () => {
68
+ assert.strictEqual(toVersRange(">0.12.7"), "vers:npm/>0.12.7");
69
+ assert.strictEqual(toVersRange("> 0.9.6"), "vers:npm/>0.9.6");
70
+ assert.strictEqual(toVersRange(">3.0.0"), "vers:npm/>3.0.0");
71
+ });
72
+
73
+ it("should handle = operator (exact version)", () => {
74
+ assert.strictEqual(toVersRange("=3.0.0-rc.1"), "vers:npm/3.0.0-rc.1");
75
+ });
76
+ });
77
+
78
+ // === Exact Versions ===
79
+ describe("exact versions", () => {
80
+ it("should convert plain version strings", () => {
81
+ assert.strictEqual(toVersRange("2.1.4"), "vers:npm/2.1.4");
82
+ assert.strictEqual(toVersRange("7.0.0"), "vers:npm/7.0.0");
83
+ assert.strictEqual(toVersRange("2.3.21"), "vers:npm/2.3.21");
84
+ });
85
+
86
+ it("should handle prerelease exact versions", () => {
87
+ assert.strictEqual(toVersRange("2.1.0-M1"), "vers:npm/2.1.0-M1");
88
+ assert.strictEqual(toVersRange("3.0.0-rc.1"), "vers:npm/3.0.0-rc.1");
89
+ });
90
+
91
+ it("should strip 'v' prefix from versions", () => {
92
+ assert.strictEqual(toVersRange("v2.0.0"), "vers:npm/2.0.0");
93
+ assert.strictEqual(
94
+ toVersRange(">=v2.0.0-alpha8"),
95
+ "vers:npm/>=2.0.0-alpha8",
96
+ );
97
+ });
98
+ });
99
+
100
+ // === AND Conditions (space-separated) ===
101
+ describe("AND conditions (space-separated)", () => {
102
+ it("should convert space-separated ranges to pipe-separated", () => {
103
+ assert.strictEqual(
104
+ toVersRange(">=2.0.0 <=4.0.4"),
105
+ "vers:npm/>=2.0.0|<=4.0.4",
106
+ );
107
+ assert.strictEqual(
108
+ toVersRange(">= 2.0.1 <3.0.2"),
109
+ "vers:npm/>=2.0.1|<3.0.2",
110
+ );
111
+ assert.strictEqual(
112
+ toVersRange(">= 15.0.0 <= 16.1.0"),
113
+ "vers:npm/>=15.0.0|<=16.1.0",
114
+ );
115
+ assert.strictEqual(
116
+ toVersRange(">=5.0.3 >=4.2.1"),
117
+ "vers:npm/>=4.2.1|>=5.0.3",
118
+ );
119
+ });
120
+
121
+ it("should handle two-part version padding in AND ranges", () => {
122
+ assert.strictEqual(
123
+ toVersRange("<=2.1 >=1.1"),
124
+ "vers:npm/>=1.1.0|<=2.1.0",
125
+ );
126
+ });
127
+ });
128
+
129
+ // === OR Conditions (||) ===
130
+ describe("OR conditions (||)", () => {
131
+ it("should convert || to single |", () => {
132
+ assert.strictEqual(
133
+ toVersRange(">=1.5.2 || >=1.4.11 <1.5.0 || >=1.3.2 <1.4.0"),
134
+ "vers:npm/>=1.3.2|<1.4.0|>=1.4.11|<1.5.0|>=1.5.2",
135
+ );
136
+ assert.strictEqual(
137
+ toVersRange(">=1.3.0 <1.3.2 || >=1.4.0 <1.4.11 || >=1.5.0 <1.5.2"),
138
+ "vers:npm/>=1.3.0|<1.3.2|>=1.4.0|<1.4.11|>=1.5.0|<1.5.2",
139
+ );
140
+ });
141
+
142
+ it("should handle complex OR ranges", () => {
143
+ assert.strictEqual(
144
+ toVersRange(
145
+ ">=3.5.1 <4.0.0 || >=4.1.3 <5.0.0 || >=5.6.1 <6.0.0 || >=6.1.2",
146
+ ),
147
+ "vers:npm/>=3.5.1|<4.0.0|>=4.1.3|<5.0.0|>=5.6.1|<6.0.0|>=6.1.2",
148
+ );
149
+ assert.strictEqual(
150
+ toVersRange(">=2.5.0 <= 3.0.0 || >=3.1.0"),
151
+ "vers:npm/>=2.5.0|<=3.0.0|>=3.1.0",
152
+ );
153
+ });
154
+
155
+ it("should handle exact versions in OR ranges", () => {
156
+ assert.strictEqual(
157
+ toVersRange("2.1.0-M1 || 2.1.0-M2"),
158
+ "vers:npm/2.1.0-M1|2.1.0-M2",
159
+ );
160
+ assert.strictEqual(
161
+ toVersRange("=3.10.1 || >=3.10.3"),
162
+ "vers:npm/3.10.1|>=3.10.3",
163
+ );
164
+ assert.strictEqual(toVersRange("2.1 || 2.6"), "vers:npm/2.1.0|2.6.0");
165
+ });
166
+ });
167
+
168
+ // === Caret Ranges (^) ===
169
+ describe("caret ranges (^)", () => {
170
+ it("should expand caret for major >= 1", () => {
171
+ assert.strictEqual(toVersRange("^1.2.9"), "vers:npm/>=1.2.9|<2.0.0");
172
+ assert.strictEqual(toVersRange("^2.0.18"), "vers:npm/>=2.0.18|<3.0.0");
173
+ assert.strictEqual(toVersRange("^4.0.8"), "vers:npm/>=4.0.8|<5.0.0");
174
+ });
175
+
176
+ it("should expand caret for major = 0, minor > 0", () => {
177
+ assert.strictEqual(
178
+ toVersRange("^0.2.1-beta"),
179
+ "vers:npm/>=0.2.1-beta|<0.3.0",
180
+ );
181
+ assert.strictEqual(toVersRange("^0.2.3"), "vers:npm/>=0.2.3|<0.3.0");
182
+ });
183
+
184
+ it("should expand caret for major = 0, minor = 0", () => {
185
+ assert.strictEqual(
186
+ toVersRange("^0.0.2-beta"),
187
+ "vers:npm/>=0.0.2-beta|<0.0.3",
188
+ );
189
+ assert.strictEqual(toVersRange("^0.0.3"), "vers:npm/>=0.0.3|<0.0.4");
190
+ });
191
+
192
+ it("should handle caret with prerelease", () => {
193
+ assert.strictEqual(
194
+ toVersRange("^1.2.3-beta.1"),
195
+ "vers:npm/>=1.2.3-beta.1|<2.0.0",
196
+ );
197
+ assert.strictEqual(
198
+ toVersRange("^5.0.0-beta.5"),
199
+ "vers:npm/>=5.0.0-beta.5|<6.0.0",
200
+ );
201
+ });
202
+
203
+ it("should handle multiple caret ranges with OR", () => {
204
+ assert.strictEqual(
205
+ toVersRange("^2.0.18 || ^3.0.16 || ^3.1.6 || ^4.0.8 || ^5.0.0-beta.5"),
206
+ "vers:npm/>=2.0.18|<3.0.0|>=3.0.16|>=3.1.6|<4.0.0|<4.0.0|>=4.0.8|>=5.0.0-beta.5|<5.0.0|<6.0.0",
207
+ );
208
+ });
209
+ });
210
+
211
+ // === Tilde Ranges (~) ===
212
+ describe("tilde ranges (~)", () => {
213
+ it("should expand tilde ranges", () => {
214
+ assert.strictEqual(toVersRange("~3.8.2"), "vers:npm/>=3.8.2|<3.9.0");
215
+ assert.strictEqual(toVersRange("~1.6.5"), "vers:npm/>=1.6.5|<1.7.0");
216
+ });
217
+
218
+ it("should handle tilde with prerelease", () => {
219
+ assert.strictEqual(
220
+ toVersRange("~0.8.0-pre"),
221
+ "vers:npm/>=0.8.0-pre|<0.8.0|>=0.8.0|<0.8.1",
222
+ );
223
+ });
224
+
225
+ it("should handle tilde in OR ranges", () => {
226
+ assert.strictEqual(
227
+ toVersRange("~1.6.5 || >=1.7.2"),
228
+ "vers:npm/>=1.6.5|<1.7.0|>=1.7.2",
229
+ );
230
+ assert.strictEqual(
231
+ toVersRange("~0.2.2 || >=0.3.2"),
232
+ "vers:npm/>=0.2.2|<0.3.0|>=0.3.2",
233
+ );
234
+ });
235
+ });
236
+
237
+ // === X-Wildcard Ranges ===
238
+ describe("x-wildcard ranges", () => {
239
+ it("should expand major.x patterns", () => {
240
+ assert.strictEqual(toVersRange(">= 1.x"), "vers:npm/>=1.0.0|<2.0.0");
241
+ assert.strictEqual(toVersRange(">= 2.2.x"), "vers:npm/>=2.2.0|<2.3.0");
242
+ });
243
+
244
+ it("should expand minor.x patterns", () => {
245
+ assert.strictEqual(toVersRange("1.2.x"), "vers:npm/>=1.2.0|<1.3.0");
246
+ assert.strictEqual(
247
+ toVersRange("2.0.x || 2.1.x"),
248
+ "vers:npm/>=2.0.0|<2.1.0|>=2.1.0|<2.2.0",
249
+ );
250
+ });
251
+ });
252
+
253
+ // === Hyphen Ranges ===
254
+ describe("hyphen ranges", () => {
255
+ it("should convert hyphen ranges to >= and <=", () => {
256
+ assert.strictEqual(
257
+ toVersRange("5.0.0 - 7.2.3"),
258
+ "vers:npm/>=5.0.0|<=7.2.3",
259
+ );
260
+ });
261
+ });
262
+
263
+ // === Version Padding ===
264
+ describe("version padding", () => {
265
+ it("should pad two-part versions to three parts", () => {
266
+ assert.strictEqual(toVersRange(">= 1.1"), "vers:npm/>=1.1.0");
267
+ assert.strictEqual(toVersRange("<= 1.0"), "vers:npm/<=1.0.0");
268
+ assert.strictEqual(toVersRange(">= 3.11"), "vers:npm/>=3.11.0");
269
+ assert.strictEqual(toVersRange("<3.11"), "vers:npm/<3.11.0");
270
+ assert.strictEqual(toVersRange(">=4.5"), "vers:npm/>=4.5.0");
271
+ });
272
+
273
+ it("should handle padded versions in ranges", () => {
274
+ assert.strictEqual(
275
+ toVersRange(">=3.11 <4 || >=4.5"),
276
+ "vers:npm/>=3.11.0|<4.0.0|>=4.5.0",
277
+ );
278
+ });
279
+ });
280
+
281
+ // === Edge Cases ===
282
+ describe("edge cases", () => {
283
+ it("should handle large version numbers", () => {
284
+ assert.strictEqual(
285
+ toVersRange("<=99.999.99999"),
286
+ "vers:npm/<=99.999.99999",
287
+ );
288
+ assert.strictEqual(toVersRange("<99.999.9999"), "vers:npm/<99.999.9999");
289
+ });
290
+
291
+ it("should handle spacing variations", () => {
292
+ assert.strictEqual(toVersRange(">= 1.6.9"), "vers:npm/>=1.6.9");
293
+ assert.strictEqual(toVersRange("< 2.0.5"), "vers:npm/<2.0.5");
294
+ assert.strictEqual(
295
+ toVersRange(">=3.4.6 < 4.0.0|| >=4.0.5"),
296
+ "vers:npm/>=3.4.6|<4.0.0|>=4.0.5",
297
+ );
298
+ });
299
+
300
+ it("should handle mixed operators in compound ranges", () => {
301
+ assert.strictEqual(
302
+ toVersRange("<5.0.3 >=5.0.0 || < 4.2.1"),
303
+ "vers:npm/<4.2.1|>=5.0.0|<5.0.3",
304
+ );
305
+ assert.strictEqual(
306
+ toVersRange("<1.6.5 || < 2.1.7 > 2.0.0"),
307
+ "vers:npm/<1.6.5|>2.0.0|<2.1.7",
308
+ );
309
+ });
310
+
311
+ it("should handle multiple exact versions", () => {
312
+ assert.strictEqual(toVersRange("1.1.2 1.2.2"), "vers:npm/1.1.2|1.2.2");
313
+ });
314
+ });
315
+ });