Skip to content

Commit af9642d

Browse files
committed
Resolve circular dependency and add length validation
- Move PackageURLBuilder export to index.ts to break circular dependency - Add length validation for name (214), namespace (512), and version (256)
1 parent 4d3b745 commit af9642d

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export {
3030
Err,
3131
Ok,
3232
PackageURL,
33-
PackageURLBuilder,
3433
PurlComponent,
3534
PurlQualifierNames,
3635
PurlType,
@@ -39,6 +38,10 @@ export {
3938
err,
4039
ok,
4140
} from './package-url.js'
41+
42+
// Import PackageURLBuilder separately to avoid circular dependency.
43+
export { PackageURLBuilder } from './package-url-builder.js'
44+
4245
export type {
4346
DownloadUrl,
4447
RepositoryUrl,

src/validate.ts

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,28 @@ function validateName(
4545
): boolean {
4646
// Support both legacy boolean parameter and new options object for backward compatibility.
4747
const opts = typeof options === 'boolean' ? { throws: options } : options
48-
return (
49-
validateRequired('name', name, opts) && validateStrings('name', name, opts)
50-
)
48+
const { throws = false } = opts ?? {}
49+
50+
// First validate it's a required string.
51+
if (
52+
!validateRequired('name', name, opts) ||
53+
!validateStrings('name', name, opts)
54+
) {
55+
return false
56+
}
57+
58+
// Validate length (npm package name limit is 214 characters).
59+
const MAX_NAME_LENGTH = 214
60+
if (typeof name === 'string' && name.length > MAX_NAME_LENGTH) {
61+
if (throws) {
62+
throw new PurlError(
63+
`"name" exceeds maximum length of ${MAX_NAME_LENGTH} characters`,
64+
)
65+
}
66+
return false
67+
}
68+
69+
return true
5170
}
5271

5372
/**
@@ -60,7 +79,27 @@ function validateNamespace(
6079
): boolean {
6180
// Support both legacy boolean parameter and new options object for backward compatibility.
6281
const opts = typeof options === 'boolean' ? { throws: options } : options
63-
return validateStrings('namespace', namespace, opts)
82+
const { throws = false } = opts ?? {}
83+
84+
if (!validateStrings('namespace', namespace, opts)) {
85+
return false
86+
}
87+
88+
// Validate length (reasonable limit for namespace).
89+
const MAX_NAMESPACE_LENGTH = 512
90+
if (
91+
typeof namespace === 'string' &&
92+
namespace.length > MAX_NAMESPACE_LENGTH
93+
) {
94+
if (throws) {
95+
throw new PurlError(
96+
`"namespace" exceeds maximum length of ${MAX_NAMESPACE_LENGTH} characters`,
97+
)
98+
}
99+
return false
100+
}
101+
102+
return true
64103
}
65104

66105
/**
@@ -311,7 +350,24 @@ function validateVersion(
311350
): boolean {
312351
// Support both legacy boolean parameter and new options object for backward compatibility.
313352
const opts = typeof options === 'boolean' ? { throws: options } : options
314-
return validateStrings('version', version, opts)
353+
const { throws = false } = opts ?? {}
354+
355+
if (!validateStrings('version', version, opts)) {
356+
return false
357+
}
358+
359+
// Validate length (reasonable limit for version strings).
360+
const MAX_VERSION_LENGTH = 256
361+
if (typeof version === 'string' && version.length > MAX_VERSION_LENGTH) {
362+
if (throws) {
363+
throw new PurlError(
364+
`"version" exceeds maximum length of ${MAX_VERSION_LENGTH} characters`,
365+
)
366+
}
367+
return false
368+
}
369+
370+
return true
315371
}
316372

317373
export {

0 commit comments

Comments
 (0)