🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@amritk/resolve-refs

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@amritk/resolve-refs - npm Package Compare versions

Comparing version
0.2.1
to
0.2.2
+36
-18
dist/resolve-refs-from-file.js

@@ -169,11 +169,13 @@ import { readFileSync } from 'node:fs';

if (typeof obj['$ref'] === 'string') {
// A `$ref` object's siblings are ignored on resolution, so we do not recurse
// into them — mirroring resolveAt's behaviour.
const { filePart } = splitRef(obj['$ref']);
if (filePart !== '')
out.add(filePart);
return out;
}
for (const key of Object.keys(obj))
// Recurse into every key — including a `$ref` node's siblings, which apply
// alongside the referenced schema (2020-12) and may carry their own refs.
for (const key of Object.keys(obj)) {
if (key === '$ref')
continue;
collectRefTargets(obj[key], out);
}
return out;

@@ -223,20 +225,36 @@ };

const cacheKey = `${targetLocation}#${pointer}`;
let resolved;
if (refCache.has(cacheKey)) {
const cached = refCache.get(cacheKey);
return cached === CYCLE ? {} : cached;
resolved = cached === CYCLE ? {} : cached;
}
refCache.set(cacheKey, CYCLE);
const target = pointer ? getByPointer(targetRoot, pointer) : targetRoot;
const resolved = resolveAt(target, targetLocation, docCache, refCache, origins);
refCache.set(cacheKey, resolved);
// Stamp the inlined node with where it was defined so a consumer can map a
// resolved-tree node back to its source document/path. Only objects/arrays are
// stamped (primitives can't key the map). First-write-wins: resolution recurses
// to the deepest `$ref` before returning, so the *definition* site stamps first;
// an outer ref that merely points (transitively) at the same object must not
// overwrite it with an intermediate location.
if (origins && resolved !== null && typeof resolved === 'object' && !origins.has(resolved)) {
origins.set(resolved, { location: targetLocation, pointer: pointerToPath(pointer) });
else {
refCache.set(cacheKey, CYCLE);
const target = pointer ? getByPointer(targetRoot, pointer) : targetRoot;
resolved = resolveAt(target, targetLocation, docCache, refCache, origins);
refCache.set(cacheKey, resolved);
// Stamp the inlined node with where it was defined so a consumer can map a
// resolved-tree node back to its source document/path. Only objects/arrays are
// stamped (primitives can't key the map). First-write-wins: resolution recurses
// to the deepest `$ref` before returning, so the *definition* site stamps first;
// an outer ref that merely points (transitively) at the same object must not
// overwrite it with an intermediate location.
if (origins && resolved !== null && typeof resolved === 'object' && !origins.has(resolved)) {
origins.set(resolved, { location: targetLocation, pointer: pointerToPath(pointer) });
}
}
return resolved;
// Keywords sibling to `$ref` apply alongside the referenced schema (2020-12),
// so preserve them by combining both in an `allOf` rather than dropping them.
const siblingKeys = Object.keys(obj).filter((key) => key !== '$ref');
if (siblingKeys.length === 0)
return resolved;
const siblings = {};
for (const key of siblingKeys)
siblings[key] = resolveAt(obj[key], baseLocation, docCache, refCache, origins);
const existingAllOf = Array.isArray(siblings['allOf']) ? siblings['allOf'] : [];
const merged = { ...siblings, allOf: [...existingAllOf, resolved] };
// Stamp the wrapper too, so origin lookups resolve for a `$ref`-with-siblings node.
if (origins && !origins.has(merged))
origins.set(merged, { location: targetLocation, pointer: pointerToPath(pointer) });
return merged;
}

@@ -243,0 +261,0 @@ const result = {};

@@ -22,16 +22,36 @@ import { getByPointer, pointerToPath } from './get-by-pointer.js';

return obj; // external ref — leave as-is
let target;
if (cache.has(ref)) {
const cached = cache.get(ref);
return cached === CYCLE ? {} : cached;
target = cached === CYCLE ? {} : cached;
}
cache.set(ref, CYCLE);
const resolved = resolveInternal(getByPointer(root, ref.slice(1)), root, cache, origins);
cache.set(ref, resolved);
// Stamp the inlined node with the path it was defined at (see resolveAt).
// First-write-wins so the deepest definition stamps before any outer ref that
// transitively points at the same object. Primitives can't key the map.
if (origins && resolved !== null && typeof resolved === 'object' && !origins.has(resolved)) {
origins.set(resolved, { location: '', pointer: pointerToPath(ref.slice(1)) });
else {
cache.set(ref, CYCLE);
target = resolveInternal(getByPointer(root, ref.slice(1)), root, cache, origins);
cache.set(ref, target);
// Stamp the inlined node with the path it was defined at (see resolveAt).
// First-write-wins so the deepest definition stamps before any outer ref that
// transitively points at the same object. Primitives can't key the map.
if (origins && target !== null && typeof target === 'object' && !origins.has(target)) {
origins.set(target, { location: '', pointer: pointerToPath(ref.slice(1)) });
}
}
return resolved;
// Per JSON Schema 2020-12, keywords sibling to `$ref` are *not* ignored: they
// apply alongside the referenced schema. Preserve them by combining both in an
// `allOf` (so a constraint present on both sides is never silently dropped)
// rather than returning the bare target. The cache always stores the
// sibling-free target so each occurrence applies its own siblings.
const siblingKeys = Object.keys(obj).filter((key) => key !== '$ref');
if (siblingKeys.length === 0)
return target;
const siblings = {};
for (const key of siblingKeys)
siblings[key] = resolveInternal(obj[key], root, cache, origins);
const existingAllOf = Array.isArray(siblings['allOf']) ? siblings['allOf'] : [];
const merged = { ...siblings, allOf: [...existingAllOf, target] };
// Stamp the wrapper too, so a consumer mapping the resolved node back to its
// origin finds one for a `$ref`-with-siblings node (not only the inner target).
if (origins && !origins.has(merged))
origins.set(merged, { location: '', pointer: pointerToPath(ref.slice(1)) });
return merged;
}

@@ -38,0 +58,0 @@ const result = {};

{
"name": "@amritk/resolve-refs",
"version": "0.2.1",
"version": "0.2.2",
"description": "Resolve and inline JSON Schema / OpenAPI $refs — internal, cross-file, and remote — with session caching and a default-deny SSRF guard.",

@@ -5,0 +5,0 @@ "module": "./dist/index.js",