@@ -218,59 +218,48 @@ const createDocumentLayout = (entries, sideBarProps, metaBarProps) => {
218218} ;
219219
220220/**
221- * Identifies and removes duplicate headings across metadata entries while tracking them
221+ * Identifies and removes duplicate headings that follow a heading with the same name
222222 * @param {Array<ApiDocMetadataEntry> } metadataEntries - API documentation metadata entries
223223 * @returns {Array<ApiDocMetadataEntry> } Processed entries with duplicates removed
224224 */
225225const removeDuplicates = metadataEntries => {
226- // Group entries by their heading's full name
227- const entriesByName = { } ;
226+ const headingMap = new Map ( ) ;
227+ let lastSeenName = null ;
228228
229- // First pass: identify headings with method signatures
229+ // Process each entry in place
230230 metadataEntries . forEach ( entry => {
231- visit ( entry . content , createQueries . UNIST . isHeading , node => {
232- if ( TYPES_WITH_METHOD_SIGNATURES . includes ( node . data . type ) ) {
231+ visit (
232+ entry . content ,
233+ createQueries . UNIST . isHeading ,
234+ ( node , index , parent ) => {
235+ // Early return if not a method signature type
236+ if ( ! TYPES_WITH_METHOD_SIGNATURES . includes ( node . data . type ) ) {
237+ return ;
238+ }
239+
233240 const fullName = getFullName ( node . data ) ;
234- ( entriesByName [ fullName ] ??= [ ] ) . push ( { entry, node } ) ;
241+
242+ if ( fullName === lastSeenName ) {
243+ // Remove duplicate heading
244+ parent . children . splice ( index , 1 ) ;
245+ // Add entry to the original heading's entries list
246+ headingMap . get ( fullName ) . entries . push ( entry ) ;
247+ } else {
248+ // Update last seen name
249+ lastSeenName = fullName ;
250+
251+ // Store original heading
252+ headingMap . set ( fullName , {
253+ node,
254+ entries : [ entry ] ,
255+ } ) ;
256+ }
235257 }
236- } ) ;
258+ ) ;
237259 } ) ;
238260
239- // Second pass: remove duplicates, keeping only the last occurrence
240- for ( const matches of Object . values ( entriesByName ) ) {
241- if ( matches . length > 1 ) {
242- // Get the last match which will be kept
243- const lastMatch = matches [ matches . length - 1 ] ;
244-
245- // Add all entries to the last entry's node data
246- lastMatch . node . data . entries = matches . map ( match => match . entry ) ;
247-
248- // Remove all but the last duplicate from their parent nodes
249- matches . slice ( 0 , - 1 ) . forEach ( match => {
250- const { entry, node } = match ;
251-
252- // Find the parent of the node to remove
253- visit ( entry . content , parent => {
254- // Check if this parent contains our node
255- const index = ( parent . children || [ ] ) . indexOf ( node ) ;
256- if ( index !== - 1 ) {
257- // Remove the node from its parent's children
258- parent . children . splice ( index , 1 ) ;
259- return true ; // Stop traversal once found and removed
260- }
261- return false ;
262- } ) ;
263- } ) ;
264- }
265- }
266-
267- // Filter out any entries that are now empty after removal
268- return metadataEntries . filter (
269- entry =>
270- entry . content &&
271- entry . content . children &&
272- entry . content . children . length > 0
273- ) ;
261+ // Filter out entries with empty content or no children
262+ return metadataEntries . filter ( entry => entry . content ?. children ?. length > 0 ) ;
274263} ;
275264
276265/**
0 commit comments