@hey-api/json-schema-ref-parser 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/bundle.ts CHANGED
@@ -157,11 +157,31 @@ const inventory$Ref = <S extends object = JSONSchema>({
157
157
  pointer = $refs._resolve($refPath, pathFromRoot, options);
158
158
  } catch (error) {
159
159
  if (error instanceof MissingPointerError) {
160
- // Log warning but continue - common in complex schema ecosystems
161
- console.warn(`Skipping unresolvable $ref: ${$refPath}`);
162
- return;
160
+ // The ref couldn't be resolved in the target file. This commonly
161
+ // happens when a wrapper file redirects via $ref to a versioned
162
+ // file, and the bundler's crawl path retains the wrapper URL.
163
+ // Try resolving the hash fragment against other files in $refs
164
+ // that might contain the target schema.
165
+ const hash = url.getHash($refPath);
166
+ if (hash) {
167
+ const baseFile = url.stripHash($refPath);
168
+ for (const filePath of Object.keys($refs._$refs)) {
169
+ if (filePath === baseFile) continue;
170
+ try {
171
+ pointer = $refs._resolve(filePath + hash, pathFromRoot, options);
172
+ if (pointer) break;
173
+ } catch {
174
+ // try next file
175
+ }
176
+ }
177
+ }
178
+ if (!pointer) {
179
+ console.warn(`Skipping unresolvable $ref: ${$refPath}`);
180
+ return;
181
+ }
182
+ } else {
183
+ throw error;
163
184
  }
164
- throw error; // Re-throw unexpected errors
165
185
  }
166
186
 
167
187
  if (pointer) {
@@ -217,8 +237,19 @@ const inventory$Ref = <S extends object = JSONSchema>({
217
237
  inventory.push(newEntry);
218
238
  inventoryLookup.add(newEntry);
219
239
 
220
- // Recursively crawl the resolved value
240
+ // Recursively crawl the resolved value.
241
+ // When the resolution followed a $ref chain to a different file,
242
+ // use the resolved file as the base path so that local $ref values
243
+ // (e.g. #/components/schemas/SiblingSchema) inside the resolved
244
+ // value resolve against the correct file.
221
245
  if (!existingEntry || external) {
246
+ let crawlPath = pointer.path;
247
+
248
+ const originalFile = url.stripHash($refPath);
249
+ if (file !== originalFile) {
250
+ crawlPath = file + url.getHash(pointer.path);
251
+ }
252
+
222
253
  crawl({
223
254
  $refs,
224
255
  indirections: indirections + 1,
@@ -227,7 +258,7 @@ const inventory$Ref = <S extends object = JSONSchema>({
227
258
  key: null,
228
259
  options,
229
260
  parent: pointer.value,
230
- path: pointer.path,
261
+ path: crawlPath,
231
262
  pathFromRoot,
232
263
  resolvedRefs,
233
264
  visitedObjects,
@@ -586,7 +617,22 @@ function remap(parser: $RefParser, inventory: Array<InventoryEntry>) {
586
617
  } catch {
587
618
  // Ignore errors
588
619
  }
589
- const proposed = `${proposedBase}_${lastToken(entry.hash)}`;
620
+
621
+ // Try without prefix first (cleaner names)
622
+ const schemaName = lastToken(entry.hash);
623
+ let proposed = schemaName;
624
+
625
+ // Check if this name would conflict with existing schemas from other files
626
+ if (!usedNamesByObj.has(container)) {
627
+ usedNamesByObj.set(container, new Set<string>(Object.keys(container || {})));
628
+ }
629
+ const used = usedNamesByObj.get(container)!;
630
+
631
+ // If the name is already used, add the file prefix
632
+ if (used.has(proposed)) {
633
+ proposed = `${proposedBase}_${schemaName}`;
634
+ }
635
+
590
636
  defName = uniqueName(container, proposed);
591
637
  namesForPrefix.set(targetKey, defName);
592
638
  // Store the resolved value under the container
package/src/index.ts CHANGED
@@ -527,20 +527,44 @@ export class $RefParser {
527
527
  }
528
528
  }
529
529
 
530
+ const HTTP_METHODS = new Set([
531
+ 'delete',
532
+ 'get',
533
+ 'head',
534
+ 'options',
535
+ 'patch',
536
+ 'post',
537
+ 'put',
538
+ 'trace',
539
+ ]);
540
+
530
541
  const srcPaths = (schema.paths || {}) as Record<string, any>;
531
542
  for (const [p, item] of Object.entries(srcPaths)) {
532
- let targetPath = p;
533
543
  if (merged.paths[p]) {
534
- const trimmed = p.startsWith('/') ? p.substring(1) : p;
535
- targetPath = `/${prefix}/${trimmed}`;
544
+ const newMethods = Object.keys(item as object).filter((k) => HTTP_METHODS.has(k));
545
+ const hasMethodConflict = newMethods.some((m) => merged.paths[p][m] !== undefined);
546
+ const rewritten = cloneAndRewrite(
547
+ item,
548
+ refMap,
549
+ tagMap,
550
+ prefix,
551
+ url.stripHash(sourcePath),
552
+ );
553
+ if (hasMethodConflict) {
554
+ const trimmed = p.startsWith('/') ? p.substring(1) : p;
555
+ merged.paths[`/${prefix}/${trimmed}`] = rewritten;
556
+ } else {
557
+ Object.assign(merged.paths[p], rewritten);
558
+ }
559
+ } else {
560
+ merged.paths[p] = cloneAndRewrite(
561
+ item,
562
+ refMap,
563
+ tagMap,
564
+ prefix,
565
+ url.stripHash(sourcePath),
566
+ );
536
567
  }
537
- merged.paths[targetPath] = cloneAndRewrite(
538
- item,
539
- refMap,
540
- tagMap,
541
- prefix,
542
- url.stripHash(sourcePath),
543
- );
544
568
  }
545
569
  }
546
570