@@ -344,33 +344,47 @@ export class PackageManagerManager {
344344
345345 // Apply filters
346346 const filteredItems = clonedItems . filter ( ( item ) => {
347- // Check if item itself matches type filter
348- const itemTypeMatch = ! filters . type || item . type === filters . type
349-
350- // Check if any subcomponents match type filter
351- const subcomponentTypeMatch =
352- item . items ?. some ( ( subItem ) => ! filters . type || subItem . type === filters . type ) ?? false
353-
354- // Type filter - include if item or any subcomponent matches
355- if ( filters . type && ! itemTypeMatch && ! subcomponentTypeMatch ) {
356- return false
347+ // Check parent item matches
348+ const itemMatches = {
349+ type : ! filters . type || item . type === filters . type ,
350+ search : ! searchTerm || containsSearchTerm ( item . name ) || containsSearchTerm ( item . description ) ,
351+ tags : ! filters . tags ?. length || ( item . tags && filters . tags . some ( ( tag ) => item . tags ! . includes ( tag ) ) ) ,
357352 }
358353
359- // Search filter
360- if ( searchTerm ) {
361- const nameMatch = containsSearchTerm ( item . name )
362- const descMatch = containsSearchTerm ( item . description )
363- const subcomponentMatch =
364- item . items ?. some (
365- ( subItem ) =>
366- subItem . metadata &&
367- ( containsSearchTerm ( subItem . metadata . name ) ||
368- containsSearchTerm ( subItem . metadata . description ) ) ,
369- ) ?? false
370- return nameMatch || descMatch || subcomponentMatch
371- }
354+ // Check subcomponent matches
355+ const subcomponentMatches =
356+ item . items ?. some ( ( subItem ) => {
357+ const subMatches = {
358+ type : ! filters . type || subItem . type === filters . type ,
359+ search :
360+ ! searchTerm ||
361+ ( subItem . metadata &&
362+ ( containsSearchTerm ( subItem . metadata . name ) ||
363+ containsSearchTerm ( subItem . metadata . description ) ) ) ,
364+ tags :
365+ ! filters . tags ?. length ||
366+ ( subItem . metadata ?. tags &&
367+ filters . tags . some ( ( tag ) => subItem . metadata ! . tags ! . includes ( tag ) ) ) ,
368+ }
372369
373- return true
370+ // When filtering by type, require exact type match
371+ // For other filters (search/tags), any match is sufficient
372+ return (
373+ subMatches . type &&
374+ ( ! searchTerm || subMatches . search ) &&
375+ ( ! filters . tags ?. length || subMatches . tags )
376+ )
377+ } ) ?? false
378+
379+ // Include item if either:
380+ // 1. Parent matches all active filters, or
381+ // 2. Parent is a package and any subcomponent matches any active filter
382+ const hasActiveFilters = filters . type || searchTerm || filters . tags ?. length
383+ if ( ! hasActiveFilters ) return true
384+
385+ const parentMatchesAll = itemMatches . type && itemMatches . search && itemMatches . tags
386+ const isPackageWithMatchingSubcomponent = item . type === "package" && subcomponentMatches
387+ return parentMatchesAll || isPackageWithMatchingSubcomponent
374388 } )
375389
376390 console . log ( "Filtered items:" , {
@@ -380,40 +394,45 @@ export class PackageManagerManager {
380394 } )
381395 // Add match info to filtered items
382396 return filteredItems . map ( ( item ) => {
383- const nameMatch = searchTerm ? containsSearchTerm ( item . name ) : true
384- const descMatch = searchTerm ? containsSearchTerm ( item . description ) : true
385- const typeMatch = filters . type ? item . type === filters . type : true
397+ // Calculate parent item matches
398+ const itemMatches = {
399+ type : ! filters . type || item . type === filters . type ,
400+ search : ! searchTerm || containsSearchTerm ( item . name ) || containsSearchTerm ( item . description ) ,
401+ tags : ! filters . tags ?. length || ( item . tags && filters . tags . some ( ( tag ) => item . tags ! . includes ( tag ) ) ) ,
402+ }
386403
387- // Process subcomponents first to determine if any match
404+ // Process subcomponents
388405 let hasMatchingSubcomponents = false
389406 if ( item . items ) {
390407 item . items = item . items . map ( ( subItem ) => {
391- // Calculate matches
392- const subNameMatch =
393- searchTerm && subItem . metadata ? containsSearchTerm ( subItem . metadata . name ) : true
394- const subDescMatch =
395- searchTerm && subItem . metadata ? containsSearchTerm ( subItem . metadata . description ) : true
396-
397- // Only calculate type match if type filter is active
398- const subTypeMatch = filters . type ? subItem . type === filters . type : false
408+ // Calculate individual filter matches for subcomponent
409+ const subMatches = {
410+ type : ! filters . type || subItem . type === filters . type ,
411+ search :
412+ ! searchTerm ||
413+ ( subItem . metadata &&
414+ ( containsSearchTerm ( subItem . metadata . name ) ||
415+ containsSearchTerm ( subItem . metadata . description ) ) ) ,
416+ tags :
417+ ! filters . tags ?. length ||
418+ ( subItem . metadata ?. tags &&
419+ filters . tags . some ( ( tag ) => subItem . metadata ! . tags ! . includes ( tag ) ) ) ,
420+ }
399421
400- // Determine if item matches based on active filters
401- const subMatched = filters . type
402- ? subNameMatch || subDescMatch || subTypeMatch
403- : subNameMatch || subDescMatch
422+ // A subcomponent matches if it matches all active filters
423+ const subMatched = subMatches . type && subMatches . search && subMatches . tags
404424
405425 if ( subMatched ) {
406426 hasMatchingSubcomponents = true
407-
408- // Only include matchReason if the item matches
427+ // Build match reason for matched subcomponent
409428 const matchReason : Record < string , boolean > = {
410- nameMatch : subNameMatch ,
411- descriptionMatch : subDescMatch ,
412- }
413-
414- // Only include type match in reason if type filter is active
415- if ( filters . type ) {
416- matchReason . typeMatch = subTypeMatch
429+ ... ( searchTerm && {
430+ nameMatch : ! ! subItem . metadata && containsSearchTerm ( subItem . metadata . name ) ,
431+ descriptionMatch :
432+ ! ! subItem . metadata && containsSearchTerm ( subItem . metadata . description ) ,
433+ } ) ,
434+ ... ( filters . type && { typeMatch : subMatches . type } ) ,
435+ ... ( filters . tags ?. length && { tagMatch : ! ! subMatches . tags } ) ,
417436 }
418437
419438 subItem . matchInfo = {
@@ -430,21 +449,34 @@ export class PackageManagerManager {
430449 } )
431450 }
432451
452+ // Build match reason for parent item
433453 const matchReason : Record < string , boolean > = {
434- nameMatch,
435- descriptionMatch : descMatch ,
454+ nameMatch : searchTerm ? containsSearchTerm ( item . name ) : true ,
455+ descriptionMatch : searchTerm ? containsSearchTerm ( item . description ) : true ,
436456 }
437457
438- // Only include typeMatch and hasMatchingSubcomponents in matchReason if relevant
439458 if ( filters . type ) {
440- matchReason . typeMatch = typeMatch
459+ matchReason . typeMatch = itemMatches . type
460+ }
461+ if ( filters . tags ?. length ) {
462+ matchReason . tagMatch = ! ! itemMatches . tags
441463 }
442464 if ( hasMatchingSubcomponents ) {
443465 matchReason . hasMatchingSubcomponents = true
444466 }
445467
468+ // Parent item is matched if:
469+ // 1. It matches all active filters directly, or
470+ // 2. It's a package and has any matching subcomponents
471+ const parentMatchesAll =
472+ ( ! filters . type || itemMatches . type ) &&
473+ ( ! searchTerm || itemMatches . search ) &&
474+ ( ! filters . tags ?. length || itemMatches . tags )
475+
476+ const isPackageWithMatchingSubcomponent = item . type === "package" && hasMatchingSubcomponents
477+
446478 item . matchInfo = {
447- matched : nameMatch || descMatch || typeMatch || hasMatchingSubcomponents ,
479+ matched : parentMatchesAll || isPackageWithMatchingSubcomponent ,
448480 matchReason,
449481 }
450482
0 commit comments