diff --git a/src/ssvc/utils/namespace_patterns.py b/src/ssvc/utils/namespace_patterns.py index eecfc57b..6d6d67ac 100644 --- a/src/ssvc/utils/namespace_patterns.py +++ b/src/ssvc/utils/namespace_patterns.py @@ -43,6 +43,5 @@ ) translation = f'\\.({reverse_dns}|{x_name})\\${bcp47}' ext_seg = f'({bcp47}|\\.{x_name}|{translation})' -lang_ext = f'(/|/{bcp47})' -extensions = f'{lang_ext}((/{ext_seg})+)?' +extensions = f'(/{bcp47}(/{ext_seg})*|/(/{ext_seg})+)' namespace = f'{base_ns}({extensions})?' diff --git a/src/ssvc/utils/ssvc_namespace_pattern.abnf b/src/ssvc/utils/ssvc_namespace_pattern.abnf index 3a83807d..277ef95e 100644 --- a/src/ssvc/utils/ssvc_namespace_pattern.abnf +++ b/src/ssvc/utils/ssvc_namespace_pattern.abnf @@ -27,12 +27,10 @@ label = ALNUMLOW [ *61ALNUMLOWDASH ALNUMLOW ] fragment-seg = 1*ALNUMLOW *( SPECIALCHAR 1*ALNUMLOW ) -extensions = lang-ext [ 1*( "/" ext-seg ) ] - -; Language extension: either / (empty language extension) -; or / (BCP-47 language code) - -lang-ext = "/" / ( "/" bcp47 ) +; Extension: +; either / (BCP-47 language code) optionally followed by ext-segs +; or / (empty language extension => default: en-US) followed by ext-segs +extensions = ("/" bcp47 *("/" ext-seg)) / ("/" 1*( "/" ext-seg )) ; Extension segment between slashes. ; - is either a language or diff --git a/src/test/test_namespaces_pattern.py b/src/test/test_namespaces_pattern.py index e0af0252..dfe14350 100644 --- a/src/test/test_namespaces_pattern.py +++ b/src/test/test_namespaces_pattern.py @@ -42,7 +42,6 @@ def setUp(self): "abc", # not in enum, but valid for the pattern "ssvc#reference-arch-1", # valid namespace with hash "x_example.test#test", - "x_example.test#test/", "x_example.test#test//.org.example#bar", "ssvc/de-DE/.org.example#reference-arch-1", # valid BCP-47 tag, reverse domain notation, hash "ssvc//.de.bund.bsi$de-DE", # BSI's translation of SSVC @@ -81,6 +80,7 @@ def setUp(self): "ssvc$de-DE", # official translations / base language are at the first extension level "anssi#800-30$fr-FR", # official translations / base language are at the first extension level "x_gov.nist#800-30$de-DE", # official translations / base language are at the first extension level + "ssvc/", # empty language extension without extension segment; see #1233 "ssvc/de-DE/example.organization##reference-arch-1", # valid BCP-47 tag, reverse domain notation, double hash "ssvc/de-DE/example.organization#multi#hash#forbidden", # valid BCP-47 tag, reverse domain notation, more than one hash per segment "x_custom.extension.", # ends with punctuation