Skip to content

Commit c9c63d8

Browse files
jdaltonclaude
andcommitted
Add validation for cocoapods, cpan, and swid package types
Implements type-specific validation rules from purl-spec: - cocoapods: Name cannot contain whitespace, plus (+) character, or begin with a period - cpan: Namespace must be UPPERCASE when present (optional component) - swid: Requires tag_id qualifier that must not be empty; GUID format tag_id must be lowercase Based on official package-url type definitions: - https://github.com/package-url/purl-spec/blob/master/types-doc/cocoapods-definition.md - https://github.com/package-url/purl-spec/blob/master/types-doc/cpan-definition.md - https://github.com/package-url/purl-spec/blob/master/types-doc/swid-definition.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent fa1386c commit c9c63d8

File tree

1 file changed

+78
-3
lines changed

1 file changed

+78
-3
lines changed

src/purl-type.ts

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,38 @@ const PurlType = createHelpersNamespaceObject(
255255
},
256256
},
257257
validate: {
258-
// TODO: cocoapods name validation
259-
// TODO: cpan namespace validation
260-
// TODO: swid qualifier validation
258+
// https://github.com/package-url/purl-spec/blob/master/types-doc/cocoapods-definition.md
259+
cocoapods(purl: PurlObject, throws: boolean) {
260+
const { name } = purl
261+
// Name cannot contain whitespace.
262+
if (/\s/.test(name)) {
263+
if (throws) {
264+
throw new PurlError(
265+
'cocoapods "name" component cannot contain whitespace',
266+
)
267+
}
268+
return false
269+
}
270+
// Name cannot contain a plus (+) character.
271+
if (name.includes('+')) {
272+
if (throws) {
273+
throw new PurlError(
274+
'cocoapods "name" component cannot contain a plus (+) character',
275+
)
276+
}
277+
return false
278+
}
279+
// Name cannot begin with a period (.).
280+
if (name.charCodeAt(0) === 46 /*'.'*/) {
281+
if (throws) {
282+
throw new PurlError(
283+
'cocoapods "name" component cannot begin with a period',
284+
)
285+
}
286+
return false
287+
}
288+
return true
289+
},
261290
// https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#conan
262291
conan(purl: PurlObject, throws: boolean) {
263292
if (isNullishOrEmptyString(purl.namespace)) {
@@ -279,6 +308,18 @@ const PurlType = createHelpersNamespaceObject(
279308
}
280309
return true
281310
},
311+
// https://github.com/package-url/purl-spec/blob/master/types-doc/cpan-definition.md
312+
cpan(purl: PurlObject, throws: boolean) {
313+
// CPAN namespace (author/publisher ID) must be uppercase when present.
314+
const { namespace } = purl
315+
if (namespace && namespace !== namespace.toUpperCase()) {
316+
if (throws) {
317+
throw new PurlError('cpan "namespace" component must be UPPERCASE')
318+
}
319+
return false
320+
}
321+
return true
322+
},
282323
// https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#cran
283324
cran(purl: PurlObject, throws: boolean) {
284325
return validateRequiredByType('cran', 'version', purl.version, throws)
@@ -480,6 +521,40 @@ const PurlType = createHelpersNamespaceObject(
480521
}
481522
return true
482523
},
524+
// https://github.com/package-url/purl-spec/blob/master/types-doc/swid-definition.md
525+
swid(purl: PurlObject, throws: boolean) {
526+
const { qualifiers } = purl
527+
// SWID requires a tag_id qualifier.
528+
const tagId = qualifiers?.['tag_id']
529+
if (!tagId) {
530+
if (throws) {
531+
throw new PurlError('swid requires a "tag_id" qualifier')
532+
}
533+
return false
534+
}
535+
// tag_id must not be empty after trimming.
536+
const tagIdStr = String(tagId).trim()
537+
if (tagIdStr.length === 0) {
538+
if (throws) {
539+
throw new PurlError('swid "tag_id" qualifier must not be empty')
540+
}
541+
return false
542+
}
543+
// If tag_id is a GUID, it must be lowercase.
544+
const guidPattern =
545+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
546+
if (guidPattern.test(tagIdStr)) {
547+
if (tagIdStr !== tagIdStr.toLowerCase()) {
548+
if (throws) {
549+
throw new PurlError(
550+
'swid "tag_id" qualifier must be lowercase when it is a GUID',
551+
)
552+
}
553+
return false
554+
}
555+
}
556+
return true
557+
},
483558
// https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#swift
484559
swift(purl: PurlObject, throws: boolean) {
485560
return (

0 commit comments

Comments
 (0)