@@ -219,8 +219,8 @@ function mapCategory(category: any, index: number): MappedCategory {
219219 const fields = category . fields || category . defaultFieldIds || [ ] ;
220220
221221 let icon = category . icon || category . iconId ;
222- if ( icon && typeof icon === 'string' && ! icon . endsWith ( '.svg' ) ) {
223- icon = ` ${ icon } .svg` ;
222+ if ( icon && typeof icon === 'string' ) {
223+ icon = normalizeIconId ( icon ) ;
224224 }
225225
226226 const definition = {
@@ -300,7 +300,7 @@ function deriveCategorySelection(categories: MappedCategory[]) {
300300async function resolveIcon ( icon : any ) : Promise < MappedIcon > {
301301 if ( ! icon ?. id ) throw new ValidationError ( 'Icon id is required' ) ;
302302
303- const id = icon . id . endsWith ( '.svg' ) ? icon . id : ` ${ icon . id } .svg` ;
303+ const id = normalizeIconId ( icon . id ) ;
304304
305305 if ( icon . svgData ) {
306306 enforceIconSize ( icon . svgData , id ) ;
@@ -324,6 +324,26 @@ async function resolveIcon(icon: any): Promise<MappedIcon> {
324324 throw new ValidationError ( `Icon ${ id } must include svgData or svgUrl` ) ;
325325}
326326
327+ const SVG_EXTENSION_PATTERN = / ( \. s v g ) + $ / i;
328+
329+ function normalizeIconId ( value : unknown ) : string {
330+ if ( typeof value !== 'string' ) {
331+ throw new ValidationError ( 'Icon id must be a non-empty string' ) ;
332+ }
333+
334+ const trimmed = value . trim ( ) ;
335+ if ( ! trimmed ) {
336+ throw new ValidationError ( 'Icon id must be a non-empty string' ) ;
337+ }
338+
339+ const normalized = trimmed . replace ( SVG_EXTENSION_PATTERN , '' ) ;
340+ if ( ! normalized ) {
341+ throw new ValidationError ( 'Icon id must include characters other than ".svg"' ) ;
342+ }
343+
344+ return normalized ;
345+ }
346+
327347function decodeDataUri ( dataUri : string ) : string {
328348 if ( ! dataUri . startsWith ( 'data:image/svg+xml,' ) ) {
329349 throw new ValidationError ( 'Invalid data URI format. Must start with "data:image/svg+xml,"' ) ;
@@ -536,4 +556,6 @@ export const __test__ = {
536556 enforceEntryCap,
537557 sanitizePathComponent,
538558 decodeDataUri,
559+ normalizeIconId,
560+ resolveIcon,
539561} ;
0 commit comments