@@ -4,22 +4,9 @@ import Pointer from './pointer';
44import $Ref from './ref' ;
55import type $Refs from './refs' ;
66import type { JSONSchema } from './types' ;
7+ import { MissingPointerError } from './util/errors' ;
78import * as url from './util/url' ;
89
9- const DEBUG_PERFORMANCE =
10- process . env . DEBUG === 'true' ||
11- ( typeof globalThis !== 'undefined' && ( globalThis as any ) . DEBUG_BUNDLE_PERFORMANCE === true ) ;
12-
13- const perf = {
14- log : ( message : string , ...args : any [ ] ) =>
15- DEBUG_PERFORMANCE && console . log ( '[PERF] ' + message , ...args ) ,
16- mark : ( name : string ) => DEBUG_PERFORMANCE && performance . mark ( name ) ,
17- measure : ( name : string , start : string , end : string ) =>
18- DEBUG_PERFORMANCE && performance . measure ( name , start , end ) ,
19- warn : ( message : string , ...args : any [ ] ) =>
20- DEBUG_PERFORMANCE && console . warn ( '[PERF] ' + message , ...args ) ,
21- } ;
22-
2310export interface InventoryEntry {
2411 $ref : any ;
2512 circular : any ;
@@ -43,8 +30,6 @@ const createInventoryLookup = () => {
4330 const lookup = new Map < string , InventoryEntry > ( ) ;
4431 const objectIds = new WeakMap < object , string > ( ) ; // Use WeakMap to avoid polluting objects
4532 let idCounter = 0 ;
46- let lookupCount = 0 ;
47- let addCount = 0 ;
4833
4934 const getObjectId = ( obj : any ) => {
5035 if ( ! objectIds . has ( obj ) ) {
@@ -59,23 +44,14 @@ const createInventoryLookup = () => {
5944
6045 return {
6146 add : ( entry : InventoryEntry ) => {
62- addCount ++ ;
6347 const key = createInventoryKey ( entry . parent , entry . key ) ;
6448 lookup . set ( key , entry ) ;
65- if ( addCount % 100 === 0 ) {
66- perf . log ( `Inventory lookup: Added ${ addCount } entries, map size: ${ lookup . size } ` ) ;
67- }
6849 } ,
6950 find : ( $refParent : any , $refKey : any ) => {
70- lookupCount ++ ;
7151 const key = createInventoryKey ( $refParent , $refKey ) ;
7252 const result = lookup . get ( key ) ;
73- if ( lookupCount % 100 === 0 ) {
74- perf . log ( `Inventory lookup: ${ lookupCount } lookups performed` ) ;
75- }
7653 return result ;
7754 } ,
78- getStats : ( ) => ( { addCount, lookupCount, mapSize : lookup . size } ) ,
7955 remove : ( entry : InventoryEntry ) => {
8056 const key = createInventoryKey ( entry . parent , entry . key ) ;
8157 lookup . delete ( key ) ;
@@ -171,29 +147,29 @@ const inventory$Ref = <S extends object = JSONSchema>({
171147 */
172148 visitedObjects ?: WeakSet < object > ;
173149} ) => {
174- perf . mark ( 'inventory-ref-start' ) ;
175150 const $ref = $refKey === null ? $refParent : $refParent [ $refKey ] ;
176151 const $refPath = url . resolve ( path , $ref . $ref ) ;
177152
178153 // Check cache first to avoid redundant resolution
179154 let pointer = resolvedRefs . get ( $refPath ) ;
180155 if ( ! pointer ) {
181- perf . mark ( 'resolve-start' ) ;
182- pointer = $refs . _resolve ( $refPath , pathFromRoot , options ) ;
183- perf . mark ( 'resolve-end' ) ;
184- perf . measure ( 'resolve-time' , 'resolve-start' , 'resolve-end' ) ;
156+ try {
157+ pointer = $refs . _resolve ( $refPath , pathFromRoot , options ) ;
158+ } catch ( error ) {
159+ if ( error instanceof MissingPointerError ) {
160+ // Log warning but continue - common in complex schema ecosystems
161+ console . warn ( `Skipping unresolvable $ref: ${ $refPath } ` ) ;
162+ return ;
163+ }
164+ throw error ; // Re-throw unexpected errors
165+ }
185166
186167 if ( pointer ) {
187168 resolvedRefs . set ( $refPath , pointer ) ;
188- perf . log ( `Cached resolved $ref: ${ $refPath } ` ) ;
189169 }
190170 }
191171
192- if ( pointer === null ) {
193- perf . mark ( 'inventory-ref-end' ) ;
194- perf . measure ( 'inventory-ref-time' , 'inventory-ref-start' , 'inventory-ref-end' ) ;
195- return ;
196- }
172+ if ( pointer === null ) return ;
197173
198174 const parsed = Pointer . parse ( pathFromRoot ) ;
199175 const depth = parsed . length ;
@@ -204,19 +180,14 @@ const inventory$Ref = <S extends object = JSONSchema>({
204180 indirections += pointer . indirections ;
205181
206182 // Check if this exact location (parent + key + pathFromRoot) has already been inventoried
207- perf . mark ( 'lookup-start' ) ;
208183 const existingEntry = inventoryLookup . find ( $refParent , $refKey ) ;
209- perf . mark ( 'lookup-end' ) ;
210- perf . measure ( 'lookup-time' , 'lookup-start' , 'lookup-end' ) ;
211184
212185 if ( existingEntry && existingEntry . pathFromRoot === pathFromRoot ) {
213186 // This exact location has already been inventoried, so we don't need to process it again
214187 if ( depth < existingEntry . depth || indirections < existingEntry . indirections ) {
215188 removeFromInventory ( inventory , existingEntry ) ;
216189 inventoryLookup . remove ( existingEntry ) ;
217190 } else {
218- perf . mark ( 'inventory-ref-end' ) ;
219- perf . measure ( 'inventory-ref-time' , 'inventory-ref-start' , 'inventory-ref-end' ) ;
220191 return ;
221192 }
222193 }
@@ -246,13 +217,8 @@ const inventory$Ref = <S extends object = JSONSchema>({
246217 inventory . push ( newEntry ) ;
247218 inventoryLookup . add ( newEntry ) ;
248219
249- perf . log (
250- `Inventoried $ref: ${ $ref . $ref } -> ${ file } ${ hash } (external: ${ external } , depth: ${ depth } )` ,
251- ) ;
252-
253220 // Recursively crawl the resolved value
254221 if ( ! existingEntry || external ) {
255- perf . mark ( 'crawl-recursive-start' ) ;
256222 crawl ( {
257223 $refs,
258224 indirections : indirections + 1 ,
@@ -266,12 +232,7 @@ const inventory$Ref = <S extends object = JSONSchema>({
266232 resolvedRefs,
267233 visitedObjects,
268234 } ) ;
269- perf . mark ( 'crawl-recursive-end' ) ;
270- perf . measure ( 'crawl-recursive-time' , 'crawl-recursive-start' , 'crawl-recursive-end' ) ;
271235 }
272-
273- perf . mark ( 'inventory-ref-end' ) ;
274- perf . measure ( 'inventory-ref-time' , 'inventory-ref-start' , 'inventory-ref-end' ) ;
275236} ;
276237
277238/**
@@ -330,13 +291,9 @@ const crawl = <S extends object = JSONSchema>({
330291
331292 if ( obj && typeof obj === 'object' && ! ArrayBuffer . isView ( obj ) ) {
332293 // Early exit if we've already processed this exact object
333- if ( visitedObjects . has ( obj ) ) {
334- perf . log ( `Skipping already visited object at ${ pathFromRoot } ` ) ;
335- return ;
336- }
294+ if ( visitedObjects . has ( obj ) ) return ;
337295
338296 if ( $Ref . isAllowed$Ref ( obj ) ) {
339- perf . log ( `Found $ref at ${ pathFromRoot } : ${ ( obj as any ) . $ref } ` ) ;
340297 inventory$Ref ( {
341298 $refKey : key ,
342299 $refParent : parent ,
@@ -369,7 +326,7 @@ const crawl = <S extends object = JSONSchema>({
369326 // This produces the shortest possible bundled references
370327 return a . length - b . length ;
371328 }
372- } ) as ( keyof typeof obj ) [ ] ;
329+ } ) as Array < keyof typeof obj > ;
373330
374331 for ( const key of keys ) {
375332 const keyPath = Pointer . join ( path , key ) ;
@@ -414,13 +371,10 @@ const crawl = <S extends object = JSONSchema>({
414371 * Remap external refs by hoisting resolved values into a shared container in the root schema
415372 * and pointing all occurrences to those internal definitions. Internal refs remain internal.
416373 */
417- function remap ( parser : $RefParser , inventory : InventoryEntry [ ] ) {
418- perf . log ( `Starting remap with ${ inventory . length } inventory entries` ) ;
419- perf . mark ( 'remap-start' ) ;
374+ function remap ( parser : $RefParser , inventory : Array < InventoryEntry > ) {
420375 const root = parser . schema as any ;
421376
422377 // Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
423- perf . mark ( 'sort-inventory-start' ) ;
424378 inventory . sort ( ( a : InventoryEntry , b : InventoryEntry ) => {
425379 if ( a . file !== b . file ) {
426380 // Group all the $refs that point to the same file
@@ -455,11 +409,6 @@ function remap(parser: $RefParser, inventory: InventoryEntry[]) {
455409 }
456410 } ) ;
457411
458- perf . mark ( 'sort-inventory-end' ) ;
459- perf . measure ( 'sort-inventory-time' , 'sort-inventory-start' , 'sort-inventory-end' ) ;
460-
461- perf . log ( `Sorted ${ inventory . length } inventory entries` ) ;
462-
463412 // Ensure or return a container by component type. Prefer OpenAPI-aware placement;
464413 // otherwise use existing root containers; otherwise create components/*.
465414 const ensureContainer = (
@@ -583,11 +532,9 @@ function remap(parser: $RefParser, inventory: InventoryEntry[]) {
583532 used . add ( name ) ;
584533 return name ;
585534 } ;
586- perf . mark ( 'remap-loop-start' ) ;
587535 for ( const entry of inventory ) {
588536 // Safety check: ensure entry and entry.$ref are valid objects
589537 if ( ! entry || ! entry . $ref || typeof entry . $ref !== 'object' ) {
590- perf . warn ( `Skipping invalid inventory entry:` , entry ) ;
591538 continue ;
592539 }
593540
@@ -654,16 +601,9 @@ function remap(parser: $RefParser, inventory: InventoryEntry[]) {
654601 entry . parent [ entry . key ] = { $ref : refPath } ;
655602 }
656603 }
657- perf . mark ( 'remap-loop-end' ) ;
658- perf . measure ( 'remap-loop-time' , 'remap-loop-start' , 'remap-loop-end' ) ;
659-
660- perf . mark ( 'remap-end' ) ;
661- perf . measure ( 'remap-total-time' , 'remap-start' , 'remap-end' ) ;
662-
663- perf . log ( `Completed remap of ${ inventory . length } entries` ) ;
664604}
665605
666- function removeFromInventory ( inventory : InventoryEntry [ ] , entry : any ) {
606+ function removeFromInventory ( inventory : Array < InventoryEntry > , entry : any ) {
667607 const index = inventory . indexOf ( entry ) ;
668608 inventory . splice ( index , 1 ) ;
669609}
@@ -676,19 +616,12 @@ function removeFromInventory(inventory: InventoryEntry[], entry: any) {
676616 * @param parser
677617 * @param options
678618 */
679- export const bundle = ( parser : $RefParser , options : ParserOptions ) => {
680- // console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);
681- perf . mark ( 'bundle-start' ) ;
682-
683- // Build an inventory of all $ref pointers in the JSON Schema
684- const inventory : InventoryEntry [ ] = [ ] ;
619+ export function bundle ( parser : $RefParser , options : ParserOptions ) : void {
620+ const inventory : Array < InventoryEntry > = [ ] ;
685621 const inventoryLookup = createInventoryLookup ( ) ;
686622
687- perf . log ( 'Starting crawl phase' ) ;
688- perf . mark ( 'crawl-phase-start' ) ;
689-
690623 const visitedObjects = new WeakSet < object > ( ) ;
691- const resolvedRefs = new Map < string , any > ( ) ; // Cache for resolved $ref targets
624+ const resolvedRefs = new Map < string , any > ( ) ;
692625
693626 crawl < JSONSchema > ( {
694627 $refs : parser . $refs ,
@@ -704,40 +637,5 @@ export const bundle = (parser: $RefParser, options: ParserOptions) => {
704637 visitedObjects,
705638 } ) ;
706639
707- perf . mark ( 'crawl-phase-end' ) ;
708- perf . measure ( 'crawl-phase-time' , 'crawl-phase-start' , 'crawl-phase-end' ) ;
709-
710- const stats = inventoryLookup . getStats ( ) ;
711- perf . log ( `Crawl phase complete. Found ${ inventory . length } $refs. Lookup stats:` , stats ) ;
712-
713- // Remap all $ref pointers
714- perf . log ( 'Starting remap phase' ) ;
715- perf . mark ( 'remap-phase-start' ) ;
716640 remap ( parser , inventory ) ;
717- perf . mark ( 'remap-phase-end' ) ;
718- perf . measure ( 'remap-phase-time' , 'remap-phase-start' , 'remap-phase-end' ) ;
719-
720- perf . mark ( 'bundle-end' ) ;
721- perf . measure ( 'bundle-total-time' , 'bundle-start' , 'bundle-end' ) ;
722-
723- perf . log ( 'Bundle complete. Performance summary:' ) ;
724-
725- // Log final stats
726- const finalStats = inventoryLookup . getStats ( ) ;
727- perf . log ( `Final inventory stats:` , finalStats ) ;
728- perf . log ( `Resolved refs cache size: ${ resolvedRefs . size } ` ) ;
729-
730- if ( DEBUG_PERFORMANCE ) {
731- // Log all performance measures
732- const measures = performance . getEntriesByType ( 'measure' ) ;
733- measures . forEach ( ( measure ) => {
734- if ( measure . name . includes ( 'time' ) ) {
735- console . log ( `${ measure . name } : ${ measure . duration . toFixed ( 2 ) } ms` ) ;
736- }
737- } ) ;
738-
739- // Clear performance marks and measures for next run
740- performance . clearMarks ( ) ;
741- performance . clearMeasures ( ) ;
742- }
743- } ;
641+ }
0 commit comments