33namespace DotnetPackaging . Msix . Core . ContentTypes ;
44
55/// <summary>
6- /// Generador de Content Types que, a partir de la colección de nombres de partes,
7- /// construye un modelo inmutable con las entradas Default y Override.
6+ /// Genera el modelo de tipos de contenido ([Content_Types].xml) emulando el comportamiento de makeappx.
87/// </summary>
98public static class ContentTypesGenerator
109{
@@ -100,7 +99,7 @@ public static class ContentTypesGenerator
10099 { "xsl" , "application/xslt+xml" } ,
101100 { "xslt" , "application/xslt+xml" } ,
102101 { "zip" , "application/x-zip-compressed" } ,
103- // Puedes agregar más según sea necesario.
102+ // Puedes agregar más según sea necesario.
104103 } ;
105104
106105
@@ -196,13 +195,13 @@ public static class ContentTypesGenerator
196195 { "xsl" , "application/xslt+xml" } ,
197196 { "xslt" , "application/xslt+xml" } ,
198197 { "zip" , "application/x-zip-compressed" } ,
199- // Puedes agregar más según sea necesario.
198+ // Puedes agregar más según sea necesario.
200199 } ;
201200
202201 // Diccionario de overrides predefinidos para partes conocidas.
203202 private static readonly Dictionary < string , string > OverrideMappings = new ( StringComparer . OrdinalIgnoreCase )
204203 {
205- // Si se incluye el manifiesto, se puede generar como override o default, según la estrategia.
204+ // Si se incluye el manifiesto, se puede generar como override o default, según la estrategia.
206205 // En el ejemplo de makeappx se trata a AppxManifest.xml como un archivo con default (al final aparece en el block map),
207206 // pero para [Content_Types].xml se suele definir override para el block map.
208207 { "/AppxBlockMap.xml" , "application/vnd.ms-appx.blockmap+xml" } ,
@@ -211,64 +210,63 @@ public static class ContentTypesGenerator
211210 // Puedes agregar otros overrides si es necesario.
212211 } ;
213212
214- /// <summary>
215- /// Genera un modelo inmutable de ContentTypesModel a partir de una colección de nombres de partes del paquete.
216- /// Se agregan entradas Default basadas en la extensión y se añaden overrides para nombres conocidos.
217- /// </summary>
218- /// <param name="partNames">Colección de nombres de partes (por ejemplo, "folder/file.ext").</param>
219- /// <returns>ContentTypesModel inmutable.</returns>
220213 public static ContentTypesModel Create ( IEnumerable < string > partNames , bool bundleMode )
221214 {
222215 if ( partNames == null )
223216 throw new ArgumentNullException ( nameof ( partNames ) ) ;
224217
225- ImmutableDictionary < string , string > . Builder defaultsBuilder = ImmutableDictionary . CreateBuilder < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
226- ImmutableList < OverrideContentType > . Builder overridesBuilder = ImmutableList . CreateBuilder < OverrideContentType > ( ) ;
218+ List < DefaultContentType > defaults = [ ] ;
219+ List < OverrideContentType > overrides = [ ] ;
220+ HashSet < string > seenExtensions = new ( StringComparer . OrdinalIgnoreCase ) ;
221+ HashSet < string > seenOverrides = new ( StringComparer . OrdinalIgnoreCase ) ;
227222
228- foreach ( var part in partNames )
223+ foreach ( string part in partNames )
229224 {
230- // Normalizamos el nombre: aseguramos que empiece con "/" y reemplazamos '\' por '/'.
231- string normalizedPart = part . StartsWith ( "/" ) ? part : "/" + part . Replace ( '\\ ' , '/' ) ;
225+ string normalizedPart = NormalizePartName ( part ) ;
232226
233- // Si el nombre coincide con algún override predefinido, lo agregamos.
234- if ( OverrideMappings . TryGetValue ( normalizedPart , out var overrideContentType ) )
227+ if ( OverrideMappings . TryGetValue ( normalizedPart , out string ? overrideContentType ) )
235228 {
236- overridesBuilder . Add ( new OverrideContentType ( normalizedPart , overrideContentType ) ) ;
229+ if ( seenOverrides . Add ( normalizedPart ) )
230+ {
231+ overrides . Add ( new OverrideContentType ( normalizedPart , overrideContentType ) ) ;
232+ }
233+
234+ continue ;
237235 }
238- else
236+
237+ string extension = GetExtension ( part ) ;
238+ if ( ! string . IsNullOrEmpty ( extension ) )
239239 {
240- // Extraemos la extensión del archivo.
241- string extension = GetExtension ( part ) ;
242- if ( ! string . IsNullOrEmpty ( extension ) )
240+ if ( seenExtensions . Add ( extension ) )
243241 {
244- if ( ! defaultsBuilder . ContainsKey ( extension ) )
242+ if ( bundleMode ? ! DefaultMappingsForBundles . TryGetValue ( extension , out var contentType ) : ! DefaultMappings . TryGetValue ( extension , out contentType ) )
245243 {
246- if ( bundleMode ? ! DefaultMappingsForBundles . TryGetValue ( extension , out var contentType ) : ! DefaultMappings . TryGetValue ( extension , out contentType ) )
247- contentType = "application/octet-stream" ;
248- defaultsBuilder . Add ( extension , contentType ) ;
244+ contentType = "application/octet-stream" ;
249245 }
246+
247+ defaults . Add ( new DefaultContentType ( extension , contentType ) ) ;
250248 }
251- else
252- {
253- // Si no hay extensión, tratamos la parte como override.
254- overridesBuilder . Add ( new OverrideContentType ( normalizedPart , "application/octet-stream" ) ) ;
255- }
249+
250+ continue ;
251+ }
252+
253+ if ( seenOverrides . Add ( normalizedPart ) )
254+ {
255+ overrides . Add ( new OverrideContentType ( normalizedPart , "application/octet-stream" ) ) ;
256256 }
257257 }
258258
259- ImmutableList < DefaultContentType > defaultsList = defaultsBuilder . Select ( kvp => new DefaultContentType ( kvp . Key , kvp . Value ) )
260- . ToImmutableList ( ) ;
261- ImmutableList < OverrideContentType > overridesList = overridesBuilder . ToImmutableList ( ) ;
259+ return new ContentTypesModel ( defaults . ToImmutableList ( ) , overrides . ToImmutableList ( ) ) ;
260+ }
262261
263- return new ContentTypesModel ( defaultsList , overridesList ) ;
262+ private static string NormalizePartName ( string part )
263+ {
264+ return part . StartsWith ( "/" ) ? part : "/" + part . Replace ( '\\ ' , '/' ) ;
264265 }
265266
266267 private static string GetExtension ( string partName )
267268 {
268- // Extrae la extensión utilizando Path.GetExtension y remueve el punto.
269269 string ext = Path . GetExtension ( partName ) ;
270- if ( ! string . IsNullOrEmpty ( ext ) )
271- return ext . TrimStart ( '.' ) . ToLowerInvariant ( ) ;
272- return string . Empty ;
270+ return string . IsNullOrEmpty ( ext ) ? string . Empty : ext . TrimStart ( '.' ) . ToLowerInvariant ( ) ;
273271 }
274272}
0 commit comments